From bd0f3345a938b35ce6a12f6150373b0955b8dd12 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 10 Jul 2011 15:24:15 -0500 Subject: Add Qt3 development HEAD version --- src/moc/moc.y | 3607 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3607 insertions(+) create mode 100644 src/moc/moc.y (limited to 'src/moc/moc.y') diff --git a/src/moc/moc.y b/src/moc/moc.y new file mode 100644 index 0000000..a88fcb6 --- /dev/null +++ b/src/moc/moc.y @@ -0,0 +1,3607 @@ +/**************************************************************************** +** +** Parser and code generator for meta object compiler +** +** Created : 930417 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +** -------------------------------------------------------------------------- +** +** This compiler reads a C++ header file with class definitions and ouputs +** C++ code to build a meta class. The meta data includes public methods +** (not constructors, destructors or operator functions), signals and slot +** definitions. The output file should be compiled and linked into the +** target application. +** +** C++ header files are assumed to have correct syntax, and we are therefore +** doing less strict checking than C++ compilers. +** +** The C++ grammar has been adopted from the "The Annotated C++ Reference +** Manual" (ARM), by Ellis and Stroustrup (Addison Wesley, 1992). +** +** Notice that this code is not possible to compile with GNU bison, instead +** use standard AT&T yacc or Berkeley yacc. +*****************************************************************************/ + +%{ +#define MOC_YACC_CODE +void yyerror( const char *msg ); + +#include "qplatformdefs.h" +#include "qasciidict.h" +#include "qdatetime.h" +#include "qdict.h" +#include "qfile.h" +#include "qdir.h" +#include "qptrlist.h" +#include "qregexp.h" +#include "qstrlist.h" +#ifdef MOC_MWERKS_PLUGIN +# ifdef Q_OS_MACX +# undef OLD_DEBUG +# ifdef DEBUG +# define OLD_DEBUG DEBUG +# undef DEBUG +# endif +# define DEBUG 0 +# ifndef __IMAGECAPTURE__ +# define __IMAGECAPTURE__ +# endif +# include +# endif +# include "mwerks_mac.h" +#endif + +#include +#include +#include + +#if defined CONST +#undef CONST +#endif +#if defined VOID +#undef VOID +#endif + +bool isEnumType( const char* type ); +int enumIndex( const char* type ); +bool isVariantType( const char* type ); +int qvariant_nameToType( const char* name ); +static void init(); // initialize +static void initClass(); // prepare for new class +static void generateClass(); // generate C++ code for class +static void initExpression(); // prepare for new expression +static void enterNameSpace( const char *name = 0 ); +static void leaveNameSpace(); +static void selectOutsideClassState(); +static void registerClassInNamespace(); +static bool suppress_func_warn = FALSE; +static void func_warn( const char *msg ); +static void moc_warn( const char *msg ); +static void moc_err( const char *s ); +static void moc_err( const char *s1, const char *s2 ); +static void operatorError(); +static void checkPropertyName( const char* ident ); + +static const char* const utype_map[] = +{ + "bool", + "int", + "double", + "QString", + "QVariant", + 0 +}; + +inline bool isIdentChar( char x ) +{ // Avoid bug in isalnum + return x == '_' || (x >= '0' && x <= '9') || + (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z'); +} + +bool validUType( QCString ctype ) +{ + if ( ctype.left(6) == "const " ) + ctype = ctype.mid( 6, ctype.length() - 6 ); + if ( ctype.right(1) == "&" ) + ctype = ctype.left( ctype.length() - 1 ); + else if ( ctype.right(1) == "*" ) + return TRUE; + + int i = -1; + while ( utype_map[++i] ) + if ( ctype == utype_map[i] ) + return TRUE; + + return isEnumType( ctype ); +} + +QCString castToUType( QCString ctype ) +{ + if ( ctype.right(1) == "&" ) + ctype = ctype.left( ctype.length() - 1 ); + if( ctype.right(1) == "]") { + int lb = ctype.findRev('['); + if(lb != -1) + ctype = ctype.left(lb) + "*"; + } + return ctype; +} + +QCString rawUType( QCString ctype ) +{ + ctype = castToUType( ctype ); + if ( ctype.left(6) == "const " ) + ctype = ctype.mid( 6, ctype.length() - 6 ); + return ctype; +} + +QCString uType( QCString ctype ) +{ + if ( !validUType( ctype ) ) { + if ( isVariantType( rawUType(ctype) ) ) + return "varptr"; + else + return "ptr"; + } + if ( ctype.left(6) == "const " ) + ctype = ctype.mid( 6, ctype.length() - 6 ); + if ( ctype.right(1) == "&" ) { + ctype = ctype.left( ctype.length() - 1 ); + } else if ( ctype.right(1) == "*" ) { + QCString raw = ctype.left( ctype.length() - 1 ); + ctype = "ptr"; + if ( raw == "char" ) + ctype = "charstar"; + else if ( raw == "QUnknownInterface" ) + ctype = "iface"; + else if ( raw == "QDispatchInterface" ) + ctype = "idisp"; + else if ( isVariantType( raw ) ) + ctype = "varptr"; + } + if ( isEnumType( ctype ) ) + ctype = "enum"; + return ctype; +} + +bool isInOut( QCString ctype ) +{ + if ( ctype.left(6) == "const " ) + return FALSE; + if ( ctype.right(1) == "&" ) + return TRUE; + if ( ctype.right(2) == "**" ) + return TRUE; + return FALSE; +} + +QCString uTypeExtra( QCString ctype ) +{ + QCString typeExtra = "0"; + if ( !validUType( ctype ) ) { + if ( isVariantType( rawUType(ctype) ) ) + typeExtra.sprintf("\"\\x%02x\"", qvariant_nameToType( rawUType(ctype) ) ); + else + typeExtra.sprintf( "\"%s\"", rawUType(ctype).data() ); + return typeExtra; + } + if ( ctype.left(6) == "const " ) + ctype = ctype.mid( 6, ctype.length() - 6 ); + if ( ctype.right(1) == "&" ) + ctype = ctype.left( ctype.length() - 1 ); + if ( ctype.right(1) == "*" ) { + QCString raw = ctype.left( ctype.length() - 1 ); + ctype = "ptr"; + if ( raw == "char" ) + ; + else if ( isVariantType( raw ) ) + typeExtra.sprintf("\"\\x%02x\"", qvariant_nameToType( raw ) ); + else + typeExtra.sprintf( "\"%s\"", raw.stripWhiteSpace().data() ); + + } else if ( isEnumType( ctype ) ) { + int idx = enumIndex( ctype ); + if ( idx >= 0 ) { + typeExtra.sprintf( "&enum_tbl[%d]", enumIndex( ctype ) ); + } else { + typeExtra.sprintf( "parentObject->enumerator(\"%s\", TRUE )", ctype.data() ); + } + typeExtra = + "\n#ifndef QT_NO_PROPERTIES\n\t " + typeExtra + + "\n#else" + "\n\t 0" + "\n#endif // QT_NO_PROPERTIES\n\t "; + } + return typeExtra; +} + +/* + Attention! + This table is copied from qvariant.cpp. If you change + one, change both. +*/ +static const int ntypes = 35; +static const char* const type_map[ntypes] = +{ + 0, + "QMap", + "QValueList", + "QString", + "QStringList", + "QFont", + "QPixmap", + "QBrush", + "QRect", + "QSize", + "QColor", + "QPalette", + "QColorGroup", + "QIconSet", + "QPoint", + "QImage", + "int", + "uint", + "bool", + "double", + "QCString", + "QPointArray", + "QRegion", + "QBitmap", + "QCursor", + "QSizePolicy", + "QDate", + "QTime", + "QDateTime", + "QByteArray", + "QBitArray", + "QKeySequence", + "QPen", + "Q_LLONG", + "Q_ULLONG" +}; + +int qvariant_nameToType( const char* name ) +{ + for ( int i = 0; i < ntypes; i++ ) { + if ( !qstrcmp( type_map[i], name ) ) + return i; + } + return 0; +} + +/* + Returns TRUE if the type is a QVariant types. +*/ +bool isVariantType( const char* type ) +{ + return qvariant_nameToType( type ) != 0; +} + +/* + Replaces '>>' with '> >' (as in 'QValueList >'). + This function must be called to produce valid C++ code. However, + the string representation still uses '>>'. +*/ +void fixRightAngles( QCString *str ) +{ + str->replace( QRegExp(">>"), "> >" ); +} + +static QCString rmWS( const char * ); + +enum Access { Private, Protected, Public }; + + +class Argument // single arg meta data +{ +public: + Argument( const char *left, const char *right, const char* argName = 0, bool isDefaultArgument = FALSE ) + { + leftType = rmWS( left ); + rightType = rmWS( right ); + if ( leftType == "void" && rightType.isEmpty() ) + leftType = ""; + + int len = leftType.length(); + + /* + Convert 'char const *' into 'const char *'. Start at index 1, + not 0, because 'const char *' is already OK. + */ + for ( int i = 1; i < len; i++ ) { + if ( leftType[i] == 'c' && + strncmp(leftType.data() + i + 1, "onst", 4) == 0 + && (i + 5 >= len || !isIdentChar(leftType[i + 5])) + && !isIdentChar(i-1) + ) { + leftType.remove( i, 5 ); + if ( leftType[i - 1] == ' ' ) + leftType.remove( i - 1, 1 ); + leftType.prepend( "const " ); + break; + } + + /* + We musn't convert 'char * const *' into 'const char **' + and we must beware of 'Bar'. + */ + if ( leftType[i] == '&' || leftType[i] == '*' || + leftType[i] == '<' ) + break; + } + + name = argName; + isDefault = isDefaultArgument; + } + + QCString leftType; + QCString rightType; + QCString name; + bool isDefault; +}; + +class ArgList : public QPtrList { // member function arg list +public: + ArgList() { setAutoDelete( TRUE ); } + ~ArgList() { clear(); } + + /* the clone has one default argument less, the orignal has all default arguments removed */ + ArgList* magicClone() { + ArgList* l = new ArgList; + bool firstDefault = FALSE; + for ( first(); current(); next() ) { + bool isDefault = current()->isDefault; + if ( !firstDefault && isDefault ) { + isDefault = FALSE; + firstDefault = TRUE; + } + l->append( new Argument( current()->leftType, current()->rightType, current()->name, isDefault ) ); + } + for ( first(); current(); ) { + if ( current()->isDefault ) + remove(); + else + next(); + } + return l; + } + + bool hasDefaultArguments() { + for ( Argument* a = first(); a; a = next() ) { + if ( a->isDefault ) + return TRUE; + } + return FALSE; + } + +}; + + +struct Function // member function meta data +{ + Access access; + QCString qualifier; // const or volatile + QCString name; + QCString type; + QCString signature; + int lineNo; + ArgList *args; + Function() { args=0;} + ~Function() { delete args; } + const char* accessAsString() { + switch ( access ) { + case Private: return "Private"; + case Protected: return "Protected"; + default: return "Public"; + } + } +}; + +class FuncList : public QPtrList { // list of member functions +public: + FuncList( bool autoDelete = FALSE ) { setAutoDelete( autoDelete ); } + + FuncList find( const char* name ) + { + FuncList result; + for ( QPtrListIterator it(*this); it.current(); ++it ) { + if ( it.current()->name == name ) + result.append( it.current() ); + } + return result; + } +}; + +class Enum : public QStrList +{ +public: + QCString name; + bool set; +}; + +class EnumList : public QPtrList { // list of property enums +public: + EnumList() { setAutoDelete(TRUE); } +}; + + +struct Property +{ + Property( int l, const char* t, const char* n, const char* s, const char* g, const char* r, + const QCString& st, const QCString& d, const QCString& sc, bool ov ) + : lineNo(l), type(t), name(n), set(s), get(g), reset(r), setfunc(0), getfunc(0), + sspec(Unspecified), gspec(Unspecified), stored( st ), + designable( d ), scriptable( sc ), override( ov ), oredEnum( -1 ) + { + /* + The Q_PROPERTY construct cannot contain any commas, since + commas separate macro arguments. We therefore expect users + to type "QMap" instead of "QMap". For + coherence, we also expect the same for + QValueList, the other template class supported by + QVariant. + */ + if ( type == "QMap" ) { + type = "QMap"; + } else if ( type == "QValueList" ) { + type = "QValueList"; + } else if ( type == "LongLong" ) { + type = "Q_LLONG"; + } else if ( type == "ULongLong" ) { + type = "Q_ULLONG"; + } + } + + int lineNo; + QCString type; + QCString name; + QCString set; + QCString get; + QCString reset; + QCString stored; + QCString designable; + QCString scriptable; + bool override; + + Function* setfunc; + Function* getfunc; + + int oredEnum; // If the enums item may be ored. That means the data type is int. + // Allowed values are 1 (True), 0 (False), and -1 (Unset) + QCString enumsettype; // contains the set function type in case of oredEnum + QCString enumgettype; // contains the get function type in case of oredEnum + + enum Specification { Unspecified, Class, Reference, Pointer, ConstCharStar }; + Specification sspec; + Specification gspec; + + bool stdSet() { + QCString s = "set"; + s += toupper( name[0] ); + s += name.mid( 1 ); + return s == set; + } + + static const char* specToString( Specification s ) + { + switch ( s ) { + case Class: + return "Class"; + case Reference: + return "Reference"; + case Pointer: + return "Pointer"; + case ConstCharStar: + return "ConstCharStar"; + default: + return "Unspecified"; + } + } +}; + +class PropList : public QPtrList { // list of properties +public: + PropList() { setAutoDelete( TRUE ); } +}; + + +struct ClassInfo +{ + ClassInfo( const char* n, const char* v ) + : name(n), value(v) + {} + QCString name; + QCString value; +}; + +class ClassInfoList : public QPtrList { // list of class infos +public: + ClassInfoList() { setAutoDelete( TRUE ); } +}; + +class parser_reg { + public: + parser_reg(); + ~parser_reg(); + + // some temporary values + QCString tmpExpression; // Used to store the characters the lexer + // is currently skipping (see addExpressionChar and friends) + QCString fileName; // file name + QCString outputFile; // output file name + QCString pchFile; // name of PCH file (used on Windows) + QStrList includeFiles; // name of #include files + QCString includePath; // #include file path + QCString qtPath; // #include qt file path + int gen_count; //number of classes generated + bool noInclude; // no #include + bool generatedCode; // no code generated + bool mocError; // moc parsing error occurred + bool hasVariantIncluded; //whether or not qvariant.h was included yet + QCString className; // name of parsed class + QCString superClassName; // name of first super class + QStrList multipleSuperClasses; // other superclasses + FuncList signals; // signal interface + FuncList slots; // slots interface + FuncList propfuncs; // all possible property access functions + FuncList funcs; // all parsed functions, including signals + EnumList enums; // enums used in properties + PropList props; // list of all properties + ClassInfoList infos; // list of all class infos + +// Used to store the values in the Q_PROPERTY macro + QCString propWrite; // set function + QCString propRead; // get function + QCString propReset; // reset function + QCString propStored; // + QCString propDesignable; // "true", "false" or function or empty if not specified + QCString propScriptable; // "true", "false" or function or empty if not specified + bool propOverride; // Wether OVERRIDE was detected + + QStrList qtEnums; // Used to store the contents of Q_ENUMS + QStrList qtSets; // Used to store the contents of Q_SETS + +}; + +static parser_reg *g = 0; + +ArgList *addArg( Argument * ); // add arg to tmpArgList + +enum Member { SignalMember, + SlotMember, + PropertyCandidateMember + }; + +void addMember( Member ); // add tmpFunc to current class +void addEnum(); // add tmpEnum to current class + +char *stradd( const char *, const char * ); // add two strings +char *stradd( const char *, const char *, // add three strings + const char * ); +char *stradd( const char *, const char *, // adds 4 strings + const char *, const char * ); + +char *straddSpc( const char *, const char * ); +char *straddSpc( const char *, const char *, + const char * ); +char *straddSpc( const char *, const char *, + const char *, const char * ); + +extern int yydebug; +bool lexDebug = FALSE; +int lineNo; // current line number +bool errorControl = FALSE; // controled errors +bool displayWarnings = TRUE; +bool skipClass; // don't generate for class +bool skipFunc; // don't generate for func +bool templateClass; // class is a template +bool templateClassOld; // previous class is a template + +ArgList *tmpArgList; // current argument list +Function *tmpFunc; // current member function +Enum *tmpEnum; // current enum +Access tmpAccess; // current access permission +Access subClassPerm; // current access permission + +bool Q_OBJECTdetected; // TRUE if current class + // contains the Q_OBJECT macro +bool Q_PROPERTYdetected; // TRUE if current class + // contains at least one Q_PROPERTY, + // Q_OVERRIDE, Q_SETS or Q_ENUMS macro +bool tmpPropOverride; // current property override setting + +int tmpYYStart; // Used to store the lexers current mode +int tmpYYStart2; // Used to store the lexers current mode + // (if tmpYYStart is already used) + +// if the format revision changes, you MUST change it in qmetaobject.h too +const int formatRevision = 26; // moc output format revision + +// if the flags change, you HAVE to change it in qmetaobject.h too +enum Flags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + EnumOrSet = 0x00000004, + UnresolvedEnum = 0x00000008, + StdSet = 0x00000100, + Override = 0x00000200, + NotDesignable = 0x00001000, + DesignableOverride = 0x00002000, + NotScriptable = 0x00004000, + ScriptableOverride = 0x00008000, + NotStored = 0x00010000, + StoredOverride = 0x00020000 +}; + + +#ifdef YYBISON +# if defined(Q_OS_WIN32) +# include +# undef isatty +extern "C" int hack_isatty( int ) + { + return 0; + } +# define isatty hack_isatty +# else +# include +# endif + +# define YYDEBUG 1 +# include "moc_yacc.h" +# include "moc_lex.cpp" +#endif //YYBISON +%} + + + + +%union { + char char_val; + int int_val; + double double_val; + char *string; + Access access; + Function *function; + ArgList *arg_list; + Argument *arg; +} + +%start declaration_seq + +%token CHAR_VAL /* value types */ +%token INT_VAL +%token DOUBLE_VAL +%token STRING +%token IDENTIFIER /* identifier string */ + +%token FRIEND /* declaration keywords */ +%token TYPEDEF +%token AUTO +%token REGISTER +%token STATIC +%token EXTERN +%token INLINE +%token VIRTUAL +%token CONST +%token VOLATILE +%token CHAR +%token SHORT +%token INT +%token LONG +%token SIGNED +%token UNSIGNED +%token FLOAT +%token DOUBLE +%token VOID +%token ENUM +%token CLASS +%token STRUCT +%token UNION +%token ASM +%token PRIVATE +%token PROTECTED +%token PUBLIC +%token OPERATOR +%token DBL_COLON +%token TRIPLE_DOT +%token TEMPLATE +%token NAMESPACE +%token USING +%token MUTABLE +%token THROW + +%token SIGNALS +%token SLOTS +%token Q_OBJECT +%token Q_PROPERTY +%token Q_OVERRIDE +%token Q_CLASSINFO +%token Q_ENUMS +%token Q_SETS + +%token READ +%token WRITE +%token STORED +%token DESIGNABLE +%token SCRIPTABLE +%token RESET + +%type class_name +%type template_class_name +%type template_spec +%type opt_base_spec + +%type base_spec +%type base_list +%type qt_macro_name +%type base_specifier +%type access_specifier +%type fct_name +%type type_name +%type simple_type_names +%type simple_type_name +%type class_key +%type complete_class_name +%type qualified_class_name +%type elaborated_type_specifier +%type whatever + +%type argument_declaration_list +%type arg_declaration_list +%type arg_declaration_list_opt +%type abstract_decl_opt +%type abstract_decl +%type argument_declaration +%type opt_exception_argument +%type cv_qualifier_list_opt +%type cv_qualifier_list +%type cv_qualifier +%type decl_specifiers +%type decl_specifier +%type decl_specs_opt +%type decl_specs +%type type_specifier +%type fct_specifier +%type declarator +%type ptr_operator +%type ptr_operators +%type ptr_operators_opt + +%type dname + +%% +declaration_seq: /* empty */ + | declaration_seq declaration + ; + +declaration: class_def +/* | template_declaration */ + | namespace_def + | namespace_alias_def + | using_declaration + | using_directive + ; + +namespace_def: named_namespace_def + | unnamed_namespace_def + ; + +named_namespace_def: NAMESPACE + IDENTIFIER { enterNameSpace($2); } + '{' { BEGIN IN_NAMESPACE; } + namespace_body + '}' { leaveNameSpace(); + selectOutsideClassState(); + } + ; + +unnamed_namespace_def: NAMESPACE { enterNameSpace(); } + '{' { BEGIN IN_NAMESPACE; } + namespace_body + '}' { leaveNameSpace(); + selectOutsideClassState(); + } + ; + +namespace_body: declaration_seq + ; + +namespace_alias_def: NAMESPACE IDENTIFIER '=' complete_class_name ';' + { selectOutsideClassState(); } + ; + + +using_directive: USING NAMESPACE { selectOutsideClassState(); } /* Skip namespace */ + ; + +using_declaration: USING IDENTIFIER { selectOutsideClassState(); } + | USING DBL_COLON { selectOutsideClassState(); } + ; + +class_def: { initClass(); } + class_specifier ';' { generateClass(); + registerClassInNamespace(); + selectOutsideClassState(); } + ; + + +/***** r.17.1 (ARM p.387 ): Keywords *****/ + +class_name: IDENTIFIER { $$ = $1; } + | template_class_name { $$ = $1; } + ; + +template_class_name: IDENTIFIER '<' template_args '>' + { g->tmpExpression = rmWS( g->tmpExpression ); + $$ = stradd( $1, "<", + g->tmpExpression, ">" ); } + ; + +/* + template_args skips all characters until it encounters a ">" (it + handles and discards sublevels of parentheses). Since the rule is + empty it must be used with care! +*/ + +template_args: /* empty */ { initExpression(); + templLevel = 1; + BEGIN IN_TEMPL_ARGS; } + ; + +/***** r.17.2 (ARM p.388): Expressions *****/ + + +/* const_expression skips all characters until it encounters either one + of "]", ")" or "," (it handles and discards sublevels of parentheses). + Since the rule is empty it must be used with care! +*/ + +const_expression: /* empty */ { initExpression(); + BEGIN IN_EXPR; } + ; + +/* def_argument is just like const expression but handles the "," + slightly differently. It was added for 3.0 as quick solution. TODO: + merge with const_expression. + */ + +def_argument: /* empty */ { BEGIN IN_DEF_ARG; } + ; + +enumerator_expression: /* empty */ { initExpression(); + BEGIN IN_ENUM; } + ; + +/***** r.17.3 (ARM p.391): Declarations *****/ + +decl_specifier: storage_class_specifier { $$ = ""; } + | type_specifier { $$ = $1; } + | fct_specifier { $$ = ""; } + | FRIEND { skipFunc = TRUE; $$ = ""; } + | TYPEDEF { skipFunc = TRUE; $$ = ""; } + ; + +decl_specifiers: decl_specs_opt type_name decl_specs_opt + { $$ = straddSpc($1,$2,$3); } + ; +decl_specs_opt: /* empty */ { $$ = ""; } + | decl_specs { $$ = $1; } + ; + +decl_specs: decl_specifier { $$ = $1; } + | decl_specs decl_specifier { $$ = straddSpc($1,$2); } + ; + +storage_class_specifier: AUTO + | REGISTER + | STATIC { skipFunc = TRUE; } + | EXTERN + ; + +fct_specifier: INLINE { } + | VIRTUAL { } + ; + +type_specifier: CONST { $$ = "const"; } + | VOLATILE { $$ = "volatile"; } + ; + +type_name: elaborated_type_specifier { $$ = $1; } + | complete_class_name { $$ = $1; } + | simple_type_names { $$ = $1; } + ; + +simple_type_names: simple_type_names simple_type_name + { $$ = straddSpc($1,$2); } + | simple_type_name { $$ = $1; } + ; + +simple_type_name: CHAR { $$ = "char"; } + | SHORT { $$ = "short"; } + | INT { $$ = "int"; } + | LONG { $$ = "long"; } + | SIGNED { $$ = "signed"; } + | UNSIGNED { $$ = "unsigned"; } + | FLOAT { $$ = "float"; } + | DOUBLE { $$ = "double"; } + | VOID { $$ = "void"; } + ; + +template_spec: TEMPLATE '<' template_args '>' + { g->tmpExpression = rmWS( g->tmpExpression ); + $$ = stradd( "template<", + g->tmpExpression, ">" ); } + ; + +opt_template_spec: /* empty */ + | template_spec { templateClassOld = templateClass; + templateClass = TRUE; + } + ; + + +class_key: opt_template_spec CLASS { $$ = "class"; } + | opt_template_spec STRUCT { $$ = "struct"; } + ; + +complete_class_name: qualified_class_name { $$ = $1; } + | DBL_COLON qualified_class_name + { $$ = stradd( "::", $2 ); } + ; + +qualified_class_name: qualified_class_name DBL_COLON class_name + { $$ = stradd( $1, "::", $3 );} + | class_name { $$ = $1; } + ; + +elaborated_type_specifier: + class_key IDENTIFIER { $$ = straddSpc($1,$2); } + | ENUM IDENTIFIER { $$ = stradd("enum ",$2); } + | UNION IDENTIFIER { $$ = stradd("union ",$2); } + ; + +/***** r.17.4 (ARM p.393): Declarators *****/ + +argument_declaration_list: arg_declaration_list_opt triple_dot_opt { $$ = $1;} + | arg_declaration_list ',' TRIPLE_DOT { $$ = $1; + func_warn("Ellipsis not supported" + " in signals and slots.\n" + "Ellipsis argument ignored."); } + ; + +arg_declaration_list_opt: /* empty */ { $$ = tmpArgList; } + | arg_declaration_list { $$ = $1; } + ; + +opt_exception_argument: /* empty */ { $$ = 0; } + | argument_declaration + ; + +triple_dot_opt: /* empty */ + | TRIPLE_DOT { func_warn("Ellipsis not supported" + " in signals and slots.\n" + "Ellipsis argument ignored."); } + + ; + +arg_declaration_list: arg_declaration_list + ',' + argument_declaration { $$ = addArg($3); } + | argument_declaration { $$ = addArg($1); } + ; + +argument_declaration: decl_specifiers abstract_decl_opt + { $$ = new Argument(straddSpc($1,$2),""); } + | decl_specifiers abstract_decl_opt + '=' { expLevel = 1; } + def_argument + { $$ = new Argument(straddSpc($1,$2),"", 0, TRUE ); } + | decl_specifiers abstract_decl_opt dname + abstract_decl_opt + { $$ = new Argument(straddSpc($1,$2),$4, $3); } + | decl_specifiers abstract_decl_opt dname + abstract_decl_opt + '=' { expLevel = 1; } + def_argument + { $$ = new Argument(straddSpc($1,$2),$4, $3, TRUE); } + ; + + +abstract_decl_opt: /* empty */ { $$ = ""; } + | abstract_decl { $$ = $1; } + ; + +abstract_decl: abstract_decl ptr_operator + { $$ = straddSpc($1,$2); } + | '[' { expLevel = 1; } + const_expression ']' + { $$ = stradd( "[", + g->tmpExpression = + g->tmpExpression.stripWhiteSpace(), "]" ); } + | abstract_decl '[' { expLevel = 1; } + const_expression ']' + { $$ = stradd( $1,"[", + g->tmpExpression = + g->tmpExpression.stripWhiteSpace(),"]" ); } + | ptr_operator { $$ = $1; } + | '(' abstract_decl ')' { $$ = $2; } + ; + +declarator: dname { $$ = ""; } + | declarator ptr_operator + { $$ = straddSpc($1,$2);} + | declarator '[' { expLevel = 1; } + const_expression ']' + { $$ = stradd( $1,"[", + g->tmpExpression = + g->tmpExpression.stripWhiteSpace(),"]" ); } + | '(' declarator ')' { $$ = $2; } + ; + +dname: IDENTIFIER + ; + +fct_decl: '(' + argument_declaration_list + ')' + cv_qualifier_list_opt + ctor_initializer_opt + exception_spec_opt + opt_identifier + fct_body_or_semicolon + { tmpFunc->args = $2; + tmpFunc->qualifier = $4; } + ; + +fct_name: IDENTIFIER /* NOTE: simplified! */ + | IDENTIFIER array_decls + { func_warn("Variable as signal or slot."); } + | IDENTIFIER '=' { expLevel=0; } + const_expression /* probably const member */ + { skipFunc = TRUE; } + | IDENTIFIER array_decls '=' { expLevel=0; } + const_expression /* probably const member */ + { skipFunc = TRUE; } + ; + + +array_decls: '[' { expLevel = 1; } + const_expression ']' + | array_decls '[' { expLevel = 1; } + const_expression ']' + + ; + +ptr_operators_opt: /* empty */ { $$ = ""; } + | ptr_operators { $$ = $1; } + ; + +ptr_operators: ptr_operator { $$ = $1; } + | ptr_operators ptr_operator { $$ = straddSpc($1,$2);} + ; + +ptr_operator: '*' cv_qualifier_list_opt { $$ = straddSpc("*",$2);} + | '&' cv_qualifier_list_opt { $$ = stradd("&",$2);} +/*! | complete_class_name + DBL_COLON + '*' + cv_qualifier_list_opt { $$ = stradd($1,"::*",$4); }*/ + ; + +cv_qualifier_list_opt: /* empty */ { $$ = ""; } + | cv_qualifier_list { $$ = $1; } + ; + +cv_qualifier_list: cv_qualifier { $$ = $1; } + | cv_qualifier_list cv_qualifier + { $$ = straddSpc($1,$2); } + ; + +cv_qualifier: CONST { $$ = "const"; } + | VOLATILE { $$ = "volatile"; } + ; + +fct_body_or_semicolon: ';' + | fct_body + | '=' INT_VAL ';' /* abstract func, INT_VAL = 0 */ + ; + +fct_body: '{' { BEGIN IN_FCT; fctLevel = 1;} + '}' { BEGIN QT_DEF; } + ; + + +/***** r.17.5 (ARM p.395): Class Declarations *****/ + +class_specifier: full_class_head + '{' { BEGIN IN_CLASS; + classPLevel = 1; + } + opt_obj_member_list + '}' { BEGIN QT_DEF; } /*catch ';'*/ + | class_head { BEGIN QT_DEF; /* -- " -- */ + skipClass = TRUE; } + | class_head '*' IDENTIFIER { BEGIN QT_DEF; /* -- " -- */ + skipClass = TRUE; } + | class_head '&' IDENTIFIER { BEGIN QT_DEF; /* -- " -- */ + skipClass = TRUE; } + | class_head + '(' IDENTIFIER ')' /* Qt macro name */ + { BEGIN QT_DEF; /* catch ';' */ + skipClass = TRUE; } + | template_spec whatever { skipClass = TRUE; + BEGIN GIMME_SEMICOLON; } + ; + +whatever: IDENTIFIER + | simple_type_name + | type_specifier + | storage_class_specifier { $$ = ""; } + | fct_specifier + ; + + +class_head: class_key + qualified_class_name { g->className = $2; + if ( g->className == "QObject" ) + Q_OBJECTdetected = TRUE; + } + | class_key + IDENTIFIER /* possible DLL EXPORT macro */ + class_name { g->className = $3; + if ( g->className == "QObject" ) + Q_OBJECTdetected = TRUE; + } + ; + +full_class_head: class_head + opt_base_spec { g->superClassName = $2; } + ; + +nested_class_head: class_key + qualified_class_name + opt_base_spec { templateClass = templateClassOld; } + ; + +exception_spec_opt: /* empty */ + | exception_spec + ; + +/* looser than the real thing */ +exception_spec: THROW '(' opt_exception_argument ')' + ; + +ctor_initializer_opt: /* empty */ + | ctor_initializer + ; + +ctor_initializer: ':' mem_initializer_list + ; + +mem_initializer_list: mem_initializer + | mem_initializer ',' mem_initializer_list + ; + +/* complete_class_name also represents IDENTIFIER */ +mem_initializer: complete_class_name '(' { expLevel = 1; } + const_expression ')' + ; + + +opt_base_spec: /* empty */ { $$ = 0; } + | base_spec { $$ = $1; } + ; + +opt_obj_member_list: /* empty */ + | obj_member_list + ; + +obj_member_list: obj_member_list obj_member_area + | obj_member_area + ; + + +qt_access_specifier: access_specifier { tmpAccess = $1; } + | SLOTS { moc_err( "Missing access specifier" + " before \"slots:\"." ); } + ; + +obj_member_area: qt_access_specifier { BEGIN QT_DEF; } + slot_area + | SIGNALS { BEGIN QT_DEF; } + ':' opt_signal_declarations + | Q_OBJECT { + if ( tmpAccess ) + moc_warn("Q_OBJECT is not in the private" + " section of the class.\n" + "Q_OBJECT is a macro that resets" + " access permission to \"private\"."); + Q_OBJECTdetected = TRUE; + } + | Q_PROPERTY { tmpYYStart = YY_START; + tmpPropOverride = FALSE; + BEGIN IN_PROPERTY; } + '(' property ')' { + BEGIN tmpYYStart; + } + opt_property_candidates + | Q_OVERRIDE { tmpYYStart = YY_START; + tmpPropOverride = TRUE; + BEGIN IN_PROPERTY; } + '(' property ')' { + BEGIN tmpYYStart; + } + opt_property_candidates + | Q_CLASSINFO { tmpYYStart = YY_START; BEGIN IN_CLASSINFO; } + '(' STRING ',' STRING ')' + { + g->infos.append( new ClassInfo( $4, $6 ) ); + BEGIN tmpYYStart; + } + opt_property_candidates + | Q_ENUMS { tmpYYStart = YY_START; BEGIN IN_PROPERTY; } + '(' qt_enums ')' { + Q_PROPERTYdetected = TRUE; + BEGIN tmpYYStart; + } + opt_property_candidates + | Q_SETS { tmpYYStart = YY_START; BEGIN IN_PROPERTY; } + '(' qt_sets ')' { + Q_PROPERTYdetected = TRUE; + BEGIN tmpYYStart; + } + opt_property_candidates + ; + +slot_area: SIGNALS ':' { moc_err( "Signals cannot " + "have access specifiers" ); } + | SLOTS ':' opt_slot_declarations + | ':' { if ( tmpAccess == Public && Q_PROPERTYdetected ) + BEGIN QT_DEF; + else + BEGIN IN_CLASS; + suppress_func_warn = TRUE; + } + opt_property_candidates + { + suppress_func_warn = FALSE; + } + | IDENTIFIER { BEGIN IN_CLASS; + if ( classPLevel != 1 ) + moc_warn( "unexpected access" + "specifier" ); + } + ; + +opt_property_candidates: /*empty*/ + | property_candidate_declarations + ; + +property_candidate_declarations: property_candidate_declarations property_candidate_declaration + | property_candidate_declaration + ; + +property_candidate_declaration: signal_or_slot { addMember( PropertyCandidateMember ); } + ; + +opt_signal_declarations: /* empty */ + | signal_declarations + ; + +signal_declarations: signal_declarations signal_declaration + | signal_declaration + ; + + +signal_declaration: signal_or_slot { addMember( SignalMember ); } + ; + +opt_slot_declarations: /* empty */ + | slot_declarations + ; + +slot_declarations: slot_declarations slot_declaration + | slot_declaration + ; + +slot_declaration: signal_or_slot { addMember( SlotMember ); } + ; + +opt_semicolons: /* empty */ + | opt_semicolons ';' + ; + +base_spec: ':' base_list { $$=$2; } + ; + +base_list : base_list ',' base_specifier { g->multipleSuperClasses.append( $3 ); } + | base_specifier + ; + +qt_macro_name: IDENTIFIER '(' IDENTIFIER ')' + { $$ = stradd( $1, "(", $3, ")" ); } + | IDENTIFIER '(' simple_type_name ')' + { $$ = stradd( $1, "(", $3, ")" ); } + ; + +base_specifier: complete_class_name {$$=$1;} + | VIRTUAL access_specifier complete_class_name {$$=$3;} + | VIRTUAL complete_class_name {$$=$2;} + | access_specifier VIRTUAL complete_class_name {$$=$3;} + | access_specifier complete_class_name {$$=$2;} + | qt_macro_name {$$=$1;} + | VIRTUAL access_specifier qt_macro_name {$$=$3;} + | VIRTUAL qt_macro_name {$$=$2;} + | access_specifier VIRTUAL qt_macro_name {$$=$3;} + | access_specifier qt_macro_name {$$=$2;} + ; + +access_specifier: PRIVATE { $$=Private; } + | PROTECTED { $$=Protected; } + | PUBLIC { $$=Public; } + ; + +operator_name: decl_specs_opt IDENTIFIER ptr_operators_opt { } + | decl_specs_opt simple_type_name ptr_operators_opt { } + | '+' + | '-' + | '*' + | '/' + | '%' + | '^' + | '&' + | '|' + | '~' + | '!' + | '=' + | '<' + | '>' + | '+' '=' + | '-' '=' + | '*' '=' + | '/' '=' + | '%' '=' + | '^' '=' + | '&' '=' + | '|' '=' + | '~' '=' + | '!' '=' + | '=' '=' + | '<' '=' + | '>' '=' + | '<' '<' + | '>' '>' + | '<' '<' '=' + | '>' '>' '=' + | '&' '&' + | '|' '|' + | '+' '+' + | '-' '-' + | ',' + | '-' '>' '*' + | '-' '>' + | '(' ')' + | '[' ']' + ; + + +opt_virtual: /* empty */ + | VIRTUAL + ; + +type_and_name: type_name fct_name + { tmpFunc->type = $1; + tmpFunc->name = $2; } + | fct_name + { tmpFunc->type = "int"; + tmpFunc->name = $1; + if ( tmpFunc->name == g->className ) + func_warn( "Constructors cannot be" + " signals or slots."); + } + | opt_virtual '~' fct_name + { tmpFunc->type = "void"; + tmpFunc->name = "~"; + tmpFunc->name += $3; + func_warn( "Destructors cannot be" + " signals or slots."); + } + | decl_specs type_name decl_specs_opt + ptr_operators_opt fct_name + { + char *tmp = + straddSpc($1,$2,$3,$4); + tmpFunc->type = rmWS(tmp); + delete [] tmp; + tmpFunc->name = $5; } + | decl_specs type_name /* probably friend decl */ + { skipFunc = TRUE; } + | type_name ptr_operators fct_name + { tmpFunc->type = + straddSpc($1,$2); + tmpFunc->name = $3; } + | type_name decl_specs ptr_operators_opt + fct_name + { tmpFunc->type = + straddSpc($1,$2,$3); + tmpFunc->name = $4; } + | type_name OPERATOR operator_name + { operatorError(); } + | OPERATOR operator_name + { operatorError(); } + | decl_specs type_name decl_specs_opt + ptr_operators_opt OPERATOR operator_name + { operatorError(); } + | type_name ptr_operators OPERATOR operator_name + { operatorError(); } + | type_name decl_specs ptr_operators_opt + OPERATOR operator_name + { operatorError(); } + ; + + +signal_or_slot: type_and_name fct_decl opt_semicolons + | type_and_name opt_bitfield ';' opt_semicolons + { func_warn("Unexpected variable declaration."); } + | type_and_name opt_bitfield ','member_declarator_list + ';' opt_semicolons + { func_warn("Unexpected variable declaration."); } + | enum_specifier opt_identifier ';' opt_semicolons + { func_warn("Unexpected enum declaration."); } + | USING complete_class_name ';' opt_semicolons + { func_warn("Unexpected using declaration."); } + | USING NAMESPACE complete_class_name ';' opt_semicolons + { func_warn("Unexpected using declaration."); } + | NAMESPACE IDENTIFIER '{' + { classPLevel++; + moc_err("Unexpected namespace declaration."); } + | nested_class_head ';' opt_semicolons + { func_warn("Unexpected class declaration.");} + | nested_class_head + '{' { func_warn("Unexpected class declaration."); + BEGIN IN_FCT; fctLevel=1; + } + '}' { BEGIN QT_DEF; } + ';' opt_semicolons + ; + + +member_declarator_list: member_declarator + | member_declarator_list ',' member_declarator + ; + +member_declarator: declarator { } + | IDENTIFIER ':' { expLevel = 0; } + const_expression + | ':' { expLevel = 0; } + const_expression + ; + +opt_bitfield: /* empty */ + | ':' { expLevel = 0; } + const_expression + ; + + +enum_specifier: ENUM enum_tail + ; + +/* optional final comma at the end of an enum list. Not really C++ but +some people still use it */ +opt_komma: /*empty*/ + | ',' + ; + +enum_tail: IDENTIFIER '{' enum_list opt_komma + '}' { BEGIN QT_DEF; + if ( tmpAccess == Public) { + tmpEnum->name = $1; + addEnum(); + } + } + | '{' enum_list opt_komma + '}' { tmpEnum->clear();} + ; + +opt_identifier: /* empty */ + | IDENTIFIER { } + ; + +enum_list: /* empty */ + | enumerator + | enum_list ',' enumerator + ; + +enumerator: IDENTIFIER { if ( tmpAccess == Public) tmpEnum->append( $1 ); } + | IDENTIFIER '=' { enumLevel=0; } + enumerator_expression { if ( tmpAccess == Public) tmpEnum->append( $1 ); } + ; + +property: IDENTIFIER IDENTIFIER + { + g->propWrite = ""; + g->propRead = ""; + g->propOverride = tmpPropOverride; + g->propReset = ""; + if ( g->propOverride ) { + g->propStored = ""; + g->propDesignable = ""; + g->propScriptable = ""; + } else { + g->propStored = "true"; + g->propDesignable = "true"; + g->propScriptable = "true"; + } + } + prop_statements + { + if ( g->propRead.isEmpty() && !g->propOverride ) + moc_err( "A property must at least feature a read method." ); + checkPropertyName( $2 ); + Q_PROPERTYdetected = TRUE; + // Avoid duplicates + for( QPtrListIterator lit( g->props ); lit.current(); ++lit ) { + if ( lit.current()->name == $2 ) { + if ( displayWarnings ) + moc_err( "Property '%s' defined twice.", + (const char*)lit.current()->name ); + } + } + g->props.append( new Property( lineNo, $1, $2, + g->propWrite, g->propRead, g->propReset, + g->propStored, g->propDesignable, + g->propScriptable, g->propOverride ) ); + } + ; + +prop_statements: /* empty */ + | READ IDENTIFIER prop_statements { g->propRead = $2; } + | WRITE IDENTIFIER prop_statements { g->propWrite = $2; } + | RESET IDENTIFIER prop_statements { g->propReset = $2; } + | STORED IDENTIFIER prop_statements { g->propStored = $2; } + | DESIGNABLE IDENTIFIER prop_statements { g->propDesignable = $2; } + | SCRIPTABLE IDENTIFIER prop_statements { g->propScriptable = $2; } + ; + +qt_enums: /* empty */ { } + | IDENTIFIER qt_enums { g->qtEnums.append( $1 ); } + ; + +qt_sets: /* empty */ { } + | IDENTIFIER qt_sets { g->qtSets.append( $1 ); } + ; + +%% + +#ifndef YYBISON +# if defined(Q_OS_WIN32) +# include +# undef isatty +extern "C" int hack_isatty( int ) +{ + return 0; +} +# define isatty hack_isatty +# else +# include +# endif +# include "moc_lex.cpp" +#endif //YYBISON + +void cleanup(); +QCString combinePath( const char *, const char * ); + +FILE *out; // output file + +parser_reg::parser_reg() : funcs(TRUE) +{ + gen_count = 0; + noInclude = FALSE; // no #include + generatedCode = FALSE; // no code generated + mocError = FALSE; // moc parsing error occurred + hasVariantIncluded = FALSE; +} + + +parser_reg::~parser_reg() +{ + slots.clear(); + signals.clear(); + propfuncs.clear(); + funcs.clear(); + infos.clear(); + props.clear(); + infos.clear(); +} + +int yyparse(); + +void replace( char *s, char c1, char c2 ); + +void setDefaultIncludeFile() +{ + if ( g->includeFiles.isEmpty() ) { + if ( g->includePath.isEmpty() ) { + if ( !g->fileName.isEmpty() && !g->outputFile.isEmpty() ) { + g->includeFiles.append( combinePath(g->fileName, g->outputFile) ); + } else { + g->includeFiles.append( g->fileName ); + } + } else { + g->includeFiles.append( combinePath(g->fileName, g->fileName) ); + } + } +} + +#ifdef Q_CC_MSVC +#define ErrorFormatString "%s(%d):" +#else +#define ErrorFormatString "%s:%d:" +#endif + +#ifndef MOC_MWERKS_PLUGIN +int main( int argc, char **argv ) +{ + init(); + + bool autoInclude = TRUE; + const char *error = 0; + g->qtPath = ""; + for ( int n=1; noutputFile = argv[++n]; + } else + g->outputFile = &opt[1]; + } else if ( opt == "i" ) { // no #include statement + g->noInclude = TRUE; + autoInclude = FALSE; + } else if ( opt[0] == 'f' ) { // produce #include statement + g->noInclude = FALSE; + autoInclude = FALSE; + if ( opt[1] ) // -fsomething.h + g->includeFiles.append( &opt[1] ); + } else if ( opt == "pch" ) { // produce #include statement for PCH + if ( !(n < argc-1) ) { + error = "Missing name of PCH file"; + break; + } + g->pchFile = argv[++n]; + } else if ( opt[0] == 'p' ) { // include file path + if ( opt[1] == '\0' ) { + if ( !(n < argc-1) ) { + error = "Missing path name for the -p option."; + break; + } + g->includePath = argv[++n]; + } else { + g->includePath = &opt[1]; + } + } else if ( opt[0] == 'q' ) { // qt include file path + if ( opt[1] == '\0' ) { + if ( !(n < argc-1) ) { + error = "Missing path name for the -q option."; + break; + } + g->qtPath = argv[++n]; + } else { + g->qtPath = &opt[1]; + } + replace(g->qtPath.data(),'\\','/'); + if ( g->qtPath.right(1) != "/" ) + g->qtPath += '/'; + } else if ( opt == "v" ) { // version number + fprintf( stderr, "Qt Meta Object Compiler version %d" + " (Qt %s)\n", formatRevision, + QT_VERSION_STR ); + cleanup(); + return 1; + } else if ( opt == "k" ) { // stop on errors + errorControl = TRUE; + } else if ( opt == "nw" ) { // don't display warnings + displayWarnings = FALSE; + } else if ( opt == "ldbg" ) { // lex debug output + lexDebug = TRUE; + } else if ( opt == "ydbg" ) { // yacc debug output + yydebug = TRUE; + } else { + error = "Invalid argument"; + } + } else { + if ( !g->fileName.isNull() ) // can handle only one file + error = "Too many input files specified"; + else + g->fileName = arg.copy(); + } + } + + if ( autoInclude ) { + int ppos = g->fileName.findRev('.'); + if ( ppos != -1 && tolower( g->fileName[ppos + 1] ) == 'h' ) + g->noInclude = FALSE; + else + g->noInclude = TRUE; + } + setDefaultIncludeFile(); + + if ( g->fileName.isNull() && !error ) { + g->fileName = "standard input"; + yyin = stdin; + } else if ( argc < 2 || error ) { // incomplete/wrong args + fprintf( stderr, "Qt meta object compiler\n" ); + if ( error ) + fprintf( stderr, "moc: %s\n", error ); + fprintf( stderr, "Usage: moc [options] \n" + "\t-o file Write output to file rather than stdout\n" + "\t-f[file] Force #include, optional file name\n" + "\t-p path Path prefix for included file\n" + "\t-i Do not generate an #include statement\n" + "\t-k Do not stop on errors\n" + "\t-nw Do not display warnings\n" + "\t-v Display version of moc\n" ); + cleanup(); + return 1; + } else { + yyin = fopen( (const char *)g->fileName, "r" ); + if ( !yyin ) { + fprintf( stderr, "moc: %s: No such file\n", (const char*)g->fileName); + cleanup(); + return 1; + } + } + if ( !g->outputFile.isEmpty() ) { // output file specified + out = fopen( (const char *)g->outputFile, "w" ); // create output file + if ( !out ) { + fprintf( stderr, "moc: Cannot create %s\n", + (const char*)g->outputFile ); + cleanup(); + return 1; + } + } else { // use stdout + out = stdout; + } + yyparse(); + fclose( yyin ); + if ( !g->outputFile.isNull() ) + fclose( out ); + + if ( !g->generatedCode && displayWarnings && !g->mocError ) { + fprintf( stderr, ErrorFormatString" Warning: %s\n", g->fileName.data(), 0, + "No relevant classes found. No output generated." ); + } + + int ret = g->mocError ? 1 : 0; + cleanup(); + return ret; +} +#else +bool qt_is_gui_used = FALSE; +#include +#include +#include +#ifdef Q_OS_MAC9 +# include +# include +# include +# include "Aliases.h" +#endif +#include "CWPluginErrors.h" +#include +#include "DropInCompilerLinker.h" +#include + +const unsigned char *p_str(const char *, int =-1); + +CWPluginContext g_ctx; + +moc_status do_moc( CWPluginContext ctx, const QCString &fin, const QCString &fout, CWFileSpec *dspec, bool i) +{ + init(); + + g_ctx = ctx; + g->noInclude = i; + g->fileName = fin; + g->outputFile = fout; + + setDefaultIncludeFile(); + + CWFileInfo fi; + memset(&fi, 0, sizeof(fi)); + fi.fullsearch = TRUE; + fi.dependencyType = cwNormalDependency; + fi.isdependentoffile = kCurrentCompiledFile; + if(CWFindAndLoadFile( ctx, fin.data(), &fi) != cwNoErr) { + cleanup(); + return moc_no_source; + } + + if(dspec) { + memcpy(dspec, &fi.filespec, sizeof(fi.filespec)); + const unsigned char *f = p_str(fout.data()); + memcpy(dspec->name, f, f[0]+1); + free(f); + } + buf_size_total = fi.filedatalength; + buf_buffer = fi.filedata; + + QCString path(""); + AliasHandle alias; + Str63 str; + AliasInfoType x = 1; + char tmp[sizeof(Str63)+2]; + if(NewAlias( NULL, &fi.filespec, &alias) != noErr) { + cleanup(); + return moc_general_error; + } + for(;;) { + GetAliasInfo(alias, x++, str); + if(!str[0]) + break; + strncpy((char *)tmp, (const char *)str+1, str[0]); + tmp[str[0]] = '\0'; + path.prepend(":"); + path.prepend((char *)tmp); + } + path.prepend("MacOS 9:"); //FIXME + + QString inpath = path + fin, outpath = path + fout; + struct stat istat, ostat; + if(stat(inpath, &istat) == -1) { + cleanup(); + return moc_no_source; + } + if(stat(outpath, &ostat) == 0 && istat.st_mtime < ostat.st_mtime) { + cleanup(); + return moc_not_time; + } + + unlink(outpath.data()); + out = fopen(outpath.data(), "w+"); + if(!out) { + cleanup(); + return moc_general_error; + } + + yyparse(); + if(out != stdout) + fclose(out); + + if(g->mocError || !g->generatedCode) { + unlink(outpath.data()); + moc_status ret = !g->generatedCode ? moc_no_qobject : moc_parse_error; + cleanup(); + return ret; + } + + cleanup(); + return moc_success; +} +#endif +void replace( char *s, char c1, char c2 ) +{ + if ( !s ) + return; + while ( *s ) { + if ( *s == c1 ) + *s = c2; + s++; + } +} + +/* + This function looks at two file names and returns the name of the + infile with a path relative to outfile. + + Examples: + + /tmp/abc, /tmp/bcd -> abc + xyz/a/bc, xyz/b/ac -> ../a/bc + /tmp/abc, xyz/klm -> /tmp/abc + */ + +QCString combinePath( const char *infile, const char *outfile ) +{ + QFileInfo inFileInfo( QDir::current(), QFile::decodeName(infile) ); + QFileInfo outFileInfo( QDir::current(), QFile::decodeName(outfile) ); + int numCommonComponents = 0; + + QStringList inSplitted = + QStringList::split( '/', inFileInfo.dir().canonicalPath(), TRUE ); + QStringList outSplitted = + QStringList::split( '/', outFileInfo.dir().canonicalPath(), TRUE ); + + while ( !inSplitted.isEmpty() && !outSplitted.isEmpty() && + inSplitted.first() == outSplitted.first() ) { + inSplitted.remove( inSplitted.begin() ); + outSplitted.remove( outSplitted.begin() ); + numCommonComponents++; + } + + if ( numCommonComponents < 2 ) { + /* + The paths don't have the same drive, or they don't have the + same root directory. Use an absolute path. + */ + return QFile::encodeName( inFileInfo.absFilePath() ); + } else { + /* + The paths have something in common. Use a path relative to + the output file. + */ + while ( !outSplitted.isEmpty() ) { + outSplitted.remove( outSplitted.begin() ); + inSplitted.prepend( ".." ); + } + inSplitted.append( inFileInfo.fileName() ); + return QFile::encodeName( inSplitted.join("/") ); + } +} + + +#define getenv hack_getenv // workaround for byacc +char *getenv() { return 0; } +char *getenv( const char * ) { return 0; } + +void init() // initialize +{ + BEGIN OUTSIDE; + if(g) + delete g; + g = new parser_reg; + lineNo = 1; + skipClass = FALSE; + skipFunc = FALSE; + tmpArgList = new ArgList; + tmpFunc = new Function; + tmpEnum = new Enum; + +#ifdef MOC_MWERKS_PLUGIN + buf_buffer = NULL; + buf_index = 0; + buf_size_total = 0; +#endif +} + +void cleanup() +{ + delete g; + g = NULL; + +#ifdef MOC_MWERKS_PLUGIN + if(buf_buffer && g_ctx) + CWReleaseFileText(g_ctx, buf_buffer); +#endif +} + +void initClass() // prepare for new class +{ + tmpAccess = Private; + subClassPerm = Private; + Q_OBJECTdetected = FALSE; + Q_PROPERTYdetected = FALSE; + skipClass = FALSE; + templateClass = FALSE; + g->slots.clear(); + g->signals.clear(); + g->propfuncs.clear(); + g->enums.clear(); + g->funcs.clear(); + g->props.clear(); + g->infos.clear(); + g->qtSets.clear(); + g->qtEnums.clear(); + g->multipleSuperClasses.clear(); +} + +struct NamespaceInfo +{ + QCString name; + int pLevelOnEntering; // Parenthesis level on entering the namespace + QDict definedClasses; // Classes defined in the namespace +}; + +QPtrList namespaces; + +void enterNameSpace( const char *name ) // prepare for new class +{ + static bool first = TRUE; + if ( first ) { + namespaces.setAutoDelete( TRUE ); + first = FALSE; + } + + NamespaceInfo *tmp = new NamespaceInfo; + if ( name ) + tmp->name = name; + tmp->pLevelOnEntering = namespacePLevel; + namespaces.append( tmp ); +} + +void leaveNameSpace() // prepare for new class +{ + NamespaceInfo *tmp = namespaces.last(); + namespacePLevel = tmp->pLevelOnEntering; + namespaces.remove(); +} + +QCString nameQualifier() +{ + QPtrListIterator iter( namespaces ); + NamespaceInfo *tmp; + QCString qualifier = ""; + for( ; (tmp = iter.current()) ; ++iter ) { + if ( !tmp->name.isNull() ) { // If not unnamed namespace + qualifier += tmp->name; + qualifier += "::"; + } + } + return qualifier; +} + +int openNameSpaceForMetaObject( FILE *out ) +{ + int levels = 0; + QPtrListIterator iter( namespaces ); + NamespaceInfo *tmp; + QCString indent = ""; + for( ; (tmp = iter.current()) ; ++iter ) { + if ( !tmp->name.isNull() ) { // If not unnamed namespace + fprintf( out, "%snamespace %s {\n", (const char *)indent, + (const char *) tmp->name ); + indent += " "; + levels++; + } + } + QCString nm = g->className; + int pos; + while( (pos = nm.find( "::" )) != -1 ) { + QCString spaceName = nm.left( pos ); + nm = nm.right( nm.length() - pos - 2 ); + if ( !spaceName.isEmpty() ) { + fprintf( out, "%snamespace %s {\n", (const char *)indent, + (const char *) spaceName ); + indent += " "; + levels++; + } + } + return levels; +} + +void closeNameSpaceForMetaObject( FILE *out, int levels ) +{ + int i; + for( i = 0 ; i < levels ; i++ ) + fprintf( out, "}" ); + if ( levels ) + fprintf( out, "\n" ); + +} + +void selectOutsideClassState() +{ + if ( namespaces.count() == 0 ) + BEGIN OUTSIDE; + else + BEGIN IN_NAMESPACE; +} + +void registerClassInNamespace() +{ + if ( namespaces.count() == 0 ) + return; + namespaces.last()->definedClasses.insert((const char *)g->className,(char*)1); +} + +// +// Remove white space from SIGNAL and SLOT names. +// This function has been copied from qobject.cpp. +// + +inline bool isSpace( char x ) +{ +#if defined(Q_CC_BOR) + /* + Borland C++ 4.5 has a weird isspace() bug. + isspace() usually works, but not here. + This implementation is sufficient for our internal use: rmWS() + */ + return (uchar) x <= 32; +#else + return isspace( (uchar) x ); +#endif +} + +static QCString rmWS( const char *src ) +{ + QCString result( qstrlen(src)+1 ); + char *d = result.data(); + char *s = (char *)src; + char last = 0; + while( *s && isSpace(*s) ) // skip leading space + s++; + while ( *s ) { + while ( *s && !isSpace(*s) ) + last = *d++ = *s++; + while ( *s && isSpace(*s) ) + s++; + if ( *s && isIdentChar(*s) && isIdentChar(last) ) + last = *d++ = ' '; + } + result.truncate( (int)(d - result.data()) ); + return result; +} + + +void initExpression() +{ + g->tmpExpression = ""; +} + +void addExpressionString( const char *s ) +{ + g->tmpExpression += s; +} + +void addExpressionChar( const char c ) +{ + g->tmpExpression += c; +} + +void yyerror( const char *msg ) // print yacc error message +{ + g->mocError = TRUE; +#ifndef MOC_MWERKS_PLUGIN + fprintf( stderr, ErrorFormatString" Error: %s\n", g->fileName.data(), lineNo, msg ); +#else + char msg2[200]; + sprintf(msg2, ErrorFormatString" Error: %s", g->fileName.data(), lineNo, msg); + CWReportMessage(g_ctx, NULL, msg2, NULL, messagetypeError, 0); +#endif + if ( errorControl ) { + if ( !g->outputFile.isEmpty() && yyin && fclose(yyin) == 0 ) + remove( g->outputFile ); + exit( -1 ); + } +} + +void moc_err( const char *s ) +{ + yyerror( s ); +} + +void moc_err( const char *s1, const char *s2 ) +{ + static char tmp[1024]; + sprintf( tmp, s1, s2 ); + yyerror( tmp ); +} + +void moc_warn( const char *msg ) +{ + if ( displayWarnings ) + fprintf( stderr, ErrorFormatString" Warning: %s\n", g->fileName.data(), lineNo, msg); +} + +void moc_warn( char *s1, char *s2 ) +{ + static char tmp[1024]; + sprintf( tmp, s1, s2 ); + if ( displayWarnings ) + fprintf( stderr, ErrorFormatString" Warning: %s\n", g->fileName.data(), lineNo, tmp); +} + +void func_warn( const char *msg ) +{ + if ( !suppress_func_warn ) + moc_warn( msg ); + skipFunc = TRUE; +} + +void operatorError() +{ + if ( !suppress_func_warn ) + moc_warn("Operator functions cannot be signals or slots."); + skipFunc = TRUE; +} + +#ifndef yywrap +int yywrap() // more files? +{ + return 1; // end of file +} +#endif + +char *stradd( const char *s1, const char *s2 ) // adds two strings +{ + char *n = new char[qstrlen(s1)+qstrlen(s2)+1]; + qstrcpy( n, s1 ); + strcat( n, s2 ); + return n; +} + +char *stradd( const char *s1, const char *s2, const char *s3 )// adds 3 strings +{ + char *n = new char[qstrlen(s1)+qstrlen(s2)+qstrlen(s3)+1]; + qstrcpy( n, s1 ); + strcat( n, s2 ); + strcat( n, s3 ); + return n; +} + +char *stradd( const char *s1, const char *s2, + const char *s3, const char *s4 )// adds 4 strings +{ + char *n = new char[qstrlen(s1)+qstrlen(s2)+qstrlen(s3)+qstrlen(s4)+1]; + qstrcpy( n, s1 ); + strcat( n, s2 ); + strcat( n, s3 ); + strcat( n, s4 ); + return n; +} + + +char *straddSpc( const char *s1, const char *s2 ) +{ + char *n = new char[qstrlen(s1)+qstrlen(s2)+2]; + qstrcpy( n, s1 ); + strcat( n, " " ); + strcat( n, s2 ); + return n; +} + +char *straddSpc( const char *s1, const char *s2, const char *s3 ) +{ + char *n = new char[qstrlen(s1)+qstrlen(s2)+qstrlen(s3)+3]; + qstrcpy( n, s1 ); + strcat( n, " " ); + strcat( n, s2 ); + strcat( n, " " ); + strcat( n, s3 ); + return n; +} + +char *straddSpc( const char *s1, const char *s2, + const char *s3, const char *s4 ) +{ + char *n = new char[qstrlen(s1)+qstrlen(s2)+qstrlen(s3)+qstrlen(s4)+4]; + qstrcpy( n, s1 ); + strcat( n, " " ); + strcat( n, s2 ); + strcat( n, " " ); + strcat( n, s3 ); + strcat( n, " " ); + strcat( n, s4 ); + return n; +} + +// Generate C++ code for building member function table + + +/* + We call B::qt_invoke() rather than A::B::qt_invoke() to + work around a bug in MSVC 6. The bug occurs if the + super-class is in a namespace and the sub-class isn't. + + Exception: If the superclass has the same name as the subclass, we + want non-MSVC users to have a working generated files. +*/ +QCString purestSuperClassName() +{ + QCString sc = g->superClassName; + QCString c = g->className; + /* + Make sure qualified template arguments (e.g., foo) + don't interfere. + */ + int pos = sc.findRev( "::", sc.find( '<' ) ); + if ( pos != -1 ) { + sc = sc.right( sc.length() - pos - 2 ); + pos = c.findRev( "::" ); + if ( pos != -1 ) + c = c.right( c.length() - pos - 2 ); + if ( sc == c ) + sc = g->superClassName; + } + return sc; +} + +QCString qualifiedClassName() +{ + return nameQualifier() + g->className; +} + +const int Slot_Num = 1; +const int Signal_Num = 2; +const int Prop_Num = 3; + +void generateFuncs( FuncList *list, const char *functype, int num ) +{ + Function *f; + for ( f=list->first(); f; f=list->next() ) { + bool hasReturnValue = f->type != "void" && (validUType( f->type ) || isVariantType( f->type) ); + + if ( hasReturnValue || !f->args->isEmpty() ) { + fprintf( out, " static const QUParameter param_%s_%d[] = {\n", functype, list->at() ); + if ( hasReturnValue ) { + if ( validUType( f->type ) ) + fprintf( out, "\t{ 0, &static_QUType_%s, %s, QUParameter::Out }", uType(f->type).data(), uTypeExtra(f->type).data() ); + else + fprintf( out, "\t{ 0, &static_QUType_QVariant, %s, QUParameter::Out }", uTypeExtra(f->type).data() ); + if ( !f->args->isEmpty() ) + fprintf( out, ",\n" ); + } + Argument* a = f->args->first(); + while ( a ) { + QCString type = a->leftType + ' ' + a->rightType; + type = type.simplifyWhiteSpace(); + if( a->name.isEmpty() ) + fprintf( out, "\t{ 0, &static_QUType_%s, %s, QUParameter::%s }", + uType( type ).data(), uTypeExtra( type ).data(), + isInOut( type ) ? "InOut" : "In" ); + else + fprintf( out, "\t{ \"%s\", &static_QUType_%s, %s, QUParameter::%s }", + a->name.data(), uType( type ).data(), uTypeExtra( type ).data(), + isInOut( type ) ? "InOut" : "In" ); + a = f->args->next(); + if ( a ) + fprintf( out, ",\n" ); + } + fprintf( out, "\n };\n"); + } + + fprintf( out, " static const QUMethod %s_%d = {", functype, list->at() ); + int n = f->args->count(); + if ( hasReturnValue ) + n++; + fprintf( out, "\"%s\", %d,", f->name.data(), n ); + if ( n ) + fprintf( out, " param_%s_%d };\n", functype, list->at() ); + else + fprintf( out, " 0 };\n" ); + + QCString typstr = ""; + int count = 0; + Argument *a = f->args->first(); + while ( a ) { + if ( !a->leftType.isEmpty() || ! a->rightType.isEmpty() ) { + if ( count++ ) + typstr += ","; + typstr += a->leftType; + typstr += a->rightType; + } + a = f->args->next(); + } + f->signature = f->name; + f->signature += "("; + f->signature += typstr; + f->signature += ")"; + } + if ( list->count() ) { + fprintf(out," static const QMetaData %s_tbl[] = {\n", functype ); + f = list->first(); + while ( f ) { + fprintf( out, "\t{ \"%s\",", f->signature.data() ); + fprintf( out, " &%s_%d,", functype, list->at() ); + fprintf( out, " QMetaData::%s }", f->accessAsString() ); + f = list->next(); + if ( f ) + fprintf( out, ",\n"); + } + fprintf( out, "\n };\n" ); + } +} + + +int enumIndex( const char* type ) +{ + int index = 0; + for( QPtrListIterator lit( g->enums ); lit.current(); ++lit ) { + if ( lit.current()->name == type ) + return index; + index++; + } + return -1; +} + +bool isEnumType( const char* type ) +{ + return enumIndex( type ) >= 0 || ( g->qtEnums.contains( type ) || g->qtSets.contains( type ) ); +} + +bool isPropertyType( const char* type ) +{ + if ( isVariantType( type ) ) + return TRUE; + + return isEnumType( type ); +} + +int generateEnums() +{ + if ( g->enums.count() == 0 ) + return 0; + + fprintf( out, "#ifndef QT_NO_PROPERTIES\n" ); + int i = 0; + for ( QPtrListIterator it( g->enums ); it.current(); ++it, ++i ) { + fprintf( out, " static const QMetaEnum::Item enum_%i[] = {\n", i ); + int k = 0; + for( QStrListIterator eit( *it.current() ); eit.current(); ++eit, ++k ) { + if ( k ) + fprintf( out, ",\n" ); + fprintf( out, "\t{ \"%s\", (int) %s::%s }", eit.current(), (const char*) g->className, eit.current() ); + } + fprintf( out, "\n };\n" ); + } + fprintf( out, " static const QMetaEnum enum_tbl[] = {\n" ); + i = 0; + for ( QPtrListIterator it2( g->enums ); it2.current(); ++it2, ++i ) { + if ( i ) + fprintf( out, ",\n" ); + fprintf( out, "\t{ \"%s\", %u, enum_%i, %s }", + (const char*)it2.current()->name, + it2.current()->count(), + i, + it2.current()->set ? "TRUE" : "FALSE" ); + } + fprintf( out, "\n };\n" ); + fprintf( out, "#endif // QT_NO_PROPERTIES\n" ); + + return g->enums.count(); +} + +int generateProps() +{ + // + // Resolve and verify property access functions + // + for( QPtrListIterator it( g->props ); it.current(); ) { + Property* p = it.current(); + ++it; + + // verify get function + if ( !p->get.isEmpty() ) { + FuncList candidates = g->propfuncs.find( p->get ); + for ( Function* f = candidates.first(); f; f = candidates.next() ) { + if ( f->qualifier != "const" ) // get functions must be const + continue; + if ( f->args && !f->args->isEmpty() ) // and must not take any arguments + continue; + QCString tmp = f->type; + Property::Specification spec = Property::Unspecified; + if ( p->type == "QCString" && (tmp == "const char*" || tmp == "const char *" ) ) { + tmp = "QCString"; + spec = Property::ConstCharStar; + } else if ( tmp.right(1) == "&" ) { + tmp = tmp.left( tmp.length() - 1 ); + spec = Property::Reference; + } else if ( tmp.right(1) == "*" ) { + tmp = tmp.left( tmp.length() - 1 ); + spec = Property::Pointer; + } else { + spec = Property::Class; + } + if ( tmp.left(6) == "const " ) + tmp = tmp.mid( 6, tmp.length() - 6 ); + tmp = tmp.simplifyWhiteSpace(); + if ( p->type == tmp ) { + // If it is an enum then it may not be a set + bool ok = TRUE; + for( QPtrListIterator lit( g->enums ); lit.current(); ++lit ) + if ( lit.current()->name == p->type && lit.current()->set ) + ok = FALSE; + if ( !ok ) continue; + p->gspec = spec; + p->getfunc = f; + p->oredEnum = 0; + break; + } + else if ( !isVariantType( p->type ) ) { + if ( tmp == "int" || tmp == "uint" || tmp == "unsigned int" ) { + // Test whether the enum is really a set (unfortunately we don't know enums of super classes) + bool ok = TRUE; + for( QPtrListIterator lit( g->enums ); lit.current(); ++lit ) + if ( lit.current()->name == p->type && !lit.current()->set ) + ok = FALSE; + if ( !ok ) continue; + p->gspec = spec; + p->getfunc = f; + p->oredEnum = 1; + p->enumgettype = tmp; + } + } + } + if ( p->getfunc == 0 ) { + if ( displayWarnings ) { + + // Is the type a set, that means, mentioned in Q_SETS? + bool set = FALSE; + for( QPtrListIterator lit( g->enums ); lit.current(); ++lit ) + if ( lit.current()->name == p->type && lit.current()->set ) + set = TRUE; + + fprintf( stderr, ErrorFormatString" Warning: Property '%s' not available.\n", + g->fileName.data(), p->lineNo, (const char*) p->name ); + fprintf( stderr, " Have been looking for public get functions \n"); + if ( !set ) { + fprintf( stderr, + " %s %s() const\n" + " %s& %s() const\n" + " const %s& %s() const\n" + " %s* %s() const\n", + (const char*) p->type, (const char*) p->get, + (const char*) p->type, (const char*) p->get, + (const char*) p->type, (const char*) p->get, + (const char*) p->type, (const char*) p->get ); + } + if ( set || !isPropertyType( p->type ) ) { + fprintf( stderr, + " int %s() const\n" + " uint %s() const\n" + " unsigned int %s() const\n", + (const char*) p->get, + (const char*) p->get, + (const char*) p->get ); + } + if ( p->type == "QCString" ) + fprintf( stderr, " const char* %s() const\n", + (const char*)p->get ); + + if ( candidates.isEmpty() ) { + fprintf( stderr, " but found nothing.\n"); + } else { + fprintf( stderr, " but only found the mismatching candidate(s)\n"); + for ( Function* f = candidates.first(); f; f = candidates.next() ) { + QCString typstr = ""; + Argument *a = f->args->first(); + int count = 0; + while ( a ) { + if ( !a->leftType.isEmpty() || ! a->rightType.isEmpty() ) { + if ( count++ ) + typstr += ","; + typstr += a->leftType; + typstr += a->rightType; + } + a = f->args->next(); + } + fprintf( stderr, " %s:%d: %s %s(%s) %s\n", g->fileName.data(), f->lineNo, + (const char*) f->type,(const char*) f->name, (const char*) typstr, + f->qualifier.isNull()?"":(const char*) f->qualifier ); + } + } + } + } + } + + // verify set function + if ( !p->set.isEmpty() ) { + FuncList candidates = g->propfuncs.find( p->set ); + for ( Function* f = candidates.first(); f; f = candidates.next() ) { + if ( !f->args || f->args->isEmpty() ) + continue; + QCString tmp = f->args->first()->leftType; + tmp = tmp.simplifyWhiteSpace(); + Property::Specification spec = Property::Unspecified; + if ( tmp.right(1) == "&" ) { + tmp = tmp.left( tmp.length() - 1 ); + spec = Property::Reference; + } + else { + spec = Property::Class; + } + if ( p->type == "QCString" && (tmp == "const char*" || tmp == "const char *" ) ) { + tmp = "QCString"; + spec = Property::ConstCharStar; + } + if ( tmp.left(6) == "const " ) + tmp = tmp.mid( 6, tmp.length() - 6 ); + tmp = tmp.simplifyWhiteSpace(); + + if ( p->type == tmp && f->args->count() == 1 ) { + // If it is an enum then it may not be a set + if ( p->oredEnum == 1 ) + continue; + bool ok = TRUE; + for( QPtrListIterator lit( g->enums ); lit.current(); ++lit ) + if ( lit.current()->name == p->type && lit.current()->set ) + ok = FALSE; + if ( !ok ) continue; + p->sspec = spec; + p->setfunc = f; + p->oredEnum = 0; + break; + } else if ( !isVariantType( p->type ) && f->args->count() == 1 ) { + if ( tmp == "int" || tmp == "uint" || tmp == "unsigned int" ) { + if ( p->oredEnum == 0 ) + continue; + // Test wether the enum is really a set (unfortunately we don't know enums of super classes) + bool ok = TRUE; + for( QPtrListIterator lit( g->enums ); lit.current(); ++lit ) + if ( lit.current()->name == p->type && !lit.current()->set ) + ok = FALSE; + if ( !ok ) continue; + p->sspec = spec; + p->setfunc = f; + p->oredEnum = 1; + p->enumsettype = tmp; + } + } + } + if ( p->setfunc == 0 ) { + if ( displayWarnings ) { + + // Is the type a set, that means, mentioned in Q_SETS ? + bool set = FALSE; + for( QPtrListIterator lit( g->enums ); lit.current(); ++lit ) + if ( lit.current()->name == p->type && lit.current()->set ) + set = TRUE; + + fprintf( stderr, ErrorFormatString" Warning: Property '%s' not writable.\n", + g->fileName.data(), p->lineNo, (const char*) p->name ); + fprintf( stderr, " Have been looking for public set functions \n"); + if ( !set && p->oredEnum != 1 ) { + fprintf( stderr, + " void %s( %s )\n" + " void %s( %s& )\n" + " void %s( const %s& )\n", + (const char*) p->set, (const char*) p->type, + (const char*) p->set, (const char*) p->type, + (const char*) p->set, (const char*) p->type ); + } + if ( set || ( !isPropertyType( p->type ) && p->oredEnum != 0 ) ) { + fprintf( stderr, + " void %s( int )\n" + " void %s( uint )\n" + " void %s( unsigned int )\n", + (const char*) p->set, + (const char*) p->set, + (const char*) p->set ); + } + + if ( p->type == "QCString" ) + fprintf( stderr, " void %s( const char* ) const\n", + (const char*) p->set ); + + if ( !candidates.isEmpty() ) { + fprintf( stderr, " but only found the mismatching candidate(s)\n"); + for ( Function* f = candidates.first(); f; f = candidates.next() ) { + QCString typstr = ""; + Argument *a = f->args->first(); + int count = 0; + while ( a ) { + if ( !a->leftType.isEmpty() || ! a->rightType.isEmpty() ) { + if ( count++ ) + typstr += ","; + typstr += a->leftType; + typstr += a->rightType; + } + a = f->args->next(); + } + fprintf( stderr, " %s:%d: %s %s(%s)\n", g->fileName.data(), f->lineNo, + (const char*) f->type,(const char*) f->name, (const char*) typstr ); + } + } + } + } + } + } + + // + // Create meta data + // + if ( g->props.count() ) { + if ( displayWarnings && !Q_OBJECTdetected ) + moc_err("The declaration of the class \"%s\" contains properties" + " but no Q_OBJECT macro.", g->className.data()); + + fprintf( out, "#ifndef QT_NO_PROPERTIES\n" ); + + fprintf( out, " static const QMetaProperty props_tbl[%d] = {\n ", g->props.count() ); + for( QPtrListIterator it( g->props ); it.current(); ++it ) { + + fprintf( out, "\t{ \"%s\",\"%s\", ", it.current()->type.data(), it.current()->name.data() ); + int flags = Invalid; + if ( !isVariantType( it.current()->type ) ) { + flags |= EnumOrSet; + if ( !isEnumType( it.current()->type ) ) + flags |= UnresolvedEnum; + } else { + flags |= qvariant_nameToType( it.current()->type ) << 24; + } + if ( it.current()->getfunc ) + flags |= Readable; + if ( it.current()->setfunc ) { + flags |= Writable; + if ( it.current()->stdSet() ) + flags |= StdSet; + } + if ( it.current()->override ) + flags |= Override; + + if ( it.current()->designable.isEmpty() ) + flags |= DesignableOverride; + else if ( it.current()->designable == "false" ) + flags |= NotDesignable; + + if ( it.current()->scriptable.isEmpty() ) + flags |= ScriptableOverride; + else if ( it.current()->scriptable == "false" ) + flags |= NotScriptable; + + if ( it.current()->stored.isEmpty() ) + flags |= StoredOverride; + else if ( it.current()->stored == "false" ) + flags |= NotStored; + + + fprintf( out, "0x%.4x, ", flags ); + fprintf( out, "&%s::metaObj, ", (const char*) qualifiedClassName() ); + if ( !isVariantType( it.current()->type ) ) { + int enumpos = -1; + int k = 0; + for( QPtrListIterator eit( g->enums ); eit.current(); ++eit, ++k ) { + if ( eit.current()->name == it.current()->type ) + enumpos = k; + } + + // Is it an enum of this class ? + if ( enumpos != -1 ) + fprintf( out, "&enum_tbl[%i], ", enumpos ); + else + fprintf( out, "0, "); + } else { + fprintf( out, "0, "); + } + fprintf( out, "-1 }" ); + if ( !it.atLast() ) + fprintf( out, ",\n" ); + else + fprintf( out, "\n" ); + } + fprintf( out, " };\n" ); + fprintf( out, "#endif // QT_NO_PROPERTIES\n" ); + } + + return g->props.count(); +} + + + +int generateClassInfos() +{ + if ( g->infos.isEmpty() ) + return 0; + + if ( displayWarnings && !Q_OBJECTdetected ) + moc_err("The declaration of the class \"%s\" contains class infos" + " but no Q_OBJECT macro.", g->className.data()); + + fprintf( out, " static const QClassInfo classinfo_tbl[] = {\n" ); + int i = 0; + for( QPtrListIterator it( g->infos ); it.current(); ++it, ++i ) { + if ( i ) + fprintf( out, ",\n" ); + fprintf( out, "\t{ \"%s\", \"%s\" }", it.current()->name.data(),it.current()->value.data() ); + } + fprintf( out, "\n };\n" ); + return i; +} + + +void generateClass() // generate C++ source code for a class +{ + const char *hdr1 = "/****************************************************************************\n" + "** %s meta object code from reading C++ file '%s'\n**\n"; + const char *hdr2 = "** Created: %s\n" + const char *hdr3 = "** WARNING! All changes made in this file will be lost!\n"; + const char *hdr4 = "*****************************************************************************/\n\n"; + int i; + + if ( skipClass ) // don't generate for class + return; + + if ( !Q_OBJECTdetected ) { + if ( g->signals.count() == 0 && g->slots.count() == 0 && g->props.count() == 0 && g->infos.count() == 0 ) + return; + if ( displayWarnings && (g->signals.count() + g->slots.count()) != 0 ) + moc_err("The declaration of the class \"%s\" contains signals " + "or slots\n\t but no Q_OBJECT macro.", g->className.data()); + } else { + if ( g->superClassName.isEmpty() ) + moc_err("The declaration of the class \"%s\" contains the\n" + "\tQ_OBJECT macro but does not inherit from any class!\n" + "\tInherit from QObject or one of its descendants" + " or remove Q_OBJECT.", g->className.data() ); + } + if ( templateClass ) { // don't generate for class + moc_err( "Sorry, Qt does not support templates that contain\n" + "\tsignals, slots or Q_OBJECT." ); + return; + } + g->generatedCode = TRUE; + g->gen_count++; + + if ( g->gen_count == 1 ) { // first class to be generated + QDateTime dt = QDateTime::currentDateTime(); + QCString dstr = dt.toString().ascii(); + QCString fn = g->fileName; + i = g->fileName.length()-1; + while ( i>0 && g->fileName[i-1] != '/' && g->fileName[i-1] != '\\' ) + i--; // skip path + if ( i >= 0 ) + fn = &g->fileName[i]; + fprintf( out, hdr1, (const char*)qualifiedClassName(),(const char*)fn); + fprintf( out, hdr2, (const char*)dstr ); + fprintf( out, hdr3 ); + fprintf( out, hdr4 ); + + if ( !g->noInclude ) { + /* + The header file might be a Qt header file with + QT_NO_COMPAT macros around signals, slots or + properties. Without the #undef, we cannot compile the + Qt library with QT_NO_COMPAT defined. + + Header files of libraries build around Qt can also use + QT_NO_COMPAT, so this #undef might be beneficial to + users of Qt, and not only to developers of Qt. + */ + fprintf( out, "#undef QT_NO_COMPAT\n" ); + + if ( !g->pchFile.isEmpty() ) + fprintf( out, "#include \"%s\" // PCH include\n", (const char*)g->pchFile ); + if ( !g->includePath.isEmpty() && g->includePath.right(1) != "/" ) + g->includePath += "/"; + + g->includeFiles.first(); + while ( g->includeFiles.current() ) { + QCString inc = g->includeFiles.current(); + if ( inc[0] != '<' && inc[0] != '"' ) { + if ( !g->includePath.isEmpty() && g->includePath != "./" ) + inc.prepend( g->includePath ); + inc = "\"" + inc + "\""; + } + fprintf( out, "#include %s\n", (const char *)inc ); + g->includeFiles.next(); + } + } + fprintf( out, "#include <%sqmetaobject.h>\n", (const char*)g->qtPath ); + fprintf( out, "#include <%sqapplication.h>\n\n", (const char*)g->qtPath ); + fprintf( out, "#include <%sprivate/qucomextra_p.h>\n", (const char*)g->qtPath ); + fprintf( out, "#if !defined(Q_MOC_OUTPUT_REVISION) || (Q_MOC_OUTPUT_REVISION != %d)\n", formatRevision ); + fprintf( out, "#error \"This file was generated using the moc from %s." + " It\"\n#error \"cannot be used with the include files from" + " this version of Qt.\"\n#error \"(The moc has changed too" + " much.)\"\n", QT_VERSION_STR ); + fprintf( out, "#endif\n\n" ); + } else { + fprintf( out, "\n\n" ); + } + + if ( !g->hasVariantIncluded ) { + bool needToIncludeVariant = !g->props.isEmpty(); + for ( Function* f =g->slots.first(); f && !needToIncludeVariant; f=g->slots.next() ) + needToIncludeVariant = ( f->type != "void" && !validUType( f->type ) && isVariantType( f->type) ); + + if ( needToIncludeVariant ) { + fprintf( out, "#include <%sqvariant.h>\n", (const char*)g->qtPath ); + g->hasVariantIncluded = TRUE; + } + } + + bool isQObject = g->className == "QObject" ; + + +// +// Generate virtual function className() +// + fprintf( out, "const char *%s::className() const\n{\n ", + (const char*)qualifiedClassName() ); + fprintf( out, "return \"%s\";\n}\n\n", (const char*)qualifiedClassName() ); + +// +// Generate static metaObj variable +// + fprintf( out, "QMetaObject *%s::metaObj = 0;\n", (const char*)qualifiedClassName()); + +// +// Generate static cleanup object variable +// + QCString cleanup = qualifiedClassName().copy(); + for ( int cnpos = 0; cnpos < cleanup.length(); cnpos++ ) { + if ( cleanup[cnpos] == ':' ) + cleanup[cnpos] = '_'; + } + + fprintf( out, "static QMetaObjectCleanUp cleanUp_%s( \"%s\", &%s::staticMetaObject );\n\n", (const char*)cleanup, (const char*)qualifiedClassName(), (const char*)qualifiedClassName() ); + +// +// Generate tr and trUtf8 member functions +// + fprintf( out, "#ifndef QT_NO_TRANSLATION\n" ); + fprintf( out, "QString %s::tr( const char *s, const char *c )\n{\n", + (const char*)qualifiedClassName() ); + fprintf( out, " if ( qApp )\n" ); + fprintf( out, "\treturn qApp->translate( \"%s\", s, c," + " QApplication::DefaultCodec );\n", + (const char*)qualifiedClassName() ); + fprintf( out, " else\n" ); + fprintf( out, "\treturn QString::fromLatin1( s );\n"); + fprintf( out, "}\n" ); + fprintf( out, "#ifndef QT_NO_TRANSLATION_UTF8\n" ); + fprintf( out, "QString %s::trUtf8( const char *s, const char *c )\n{\n", + (const char*)qualifiedClassName() ); + fprintf( out, " if ( qApp )\n" ); + fprintf( out, "\treturn qApp->translate( \"%s\", s, c," + " QApplication::UnicodeUTF8 );\n", + (const char*)qualifiedClassName() ); + fprintf( out, " else\n" ); + fprintf( out, "\treturn QString::fromUtf8( s );\n" ); + fprintf( out, "}\n" ); + fprintf( out, "#endif // QT_NO_TRANSLATION_UTF8\n\n" ); + fprintf( out, "#endif // QT_NO_TRANSLATION\n\n" ); + +// +// Generate staticMetaObject member function +// + fprintf( out, "QMetaObject* %s::staticMetaObject()\n{\n", (const char*)qualifiedClassName() ); + fprintf( out, " if ( metaObj )\n\treturn metaObj;\n" ); + if ( isQObject ) + fprintf( out, " QMetaObject* parentObject = staticQtMetaObject();\n" ); + else if ( !g->superClassName.isEmpty() ) + fprintf( out, " QMetaObject* parentObject = %s::staticMetaObject();\n", (const char*)g->superClassName ); + else + fprintf( out, " QMetaObject* parentObject = 0;\n" ); + +// +// Build the classinfo array +// + int n_infos = generateClassInfos(); + +// Build the enums array +// Enums HAVE to be generated BEFORE the properties and slots +// + int n_enums = generateEnums(); + +// +// Build slots array in staticMetaObject() +// + generateFuncs( &g->slots, "slot", Slot_Num ); + +// +// Build signals array in staticMetaObject() +// + generateFuncs( &g->signals, "signal", Signal_Num ); + +// +// Build property array in staticMetaObject() +// + int n_props = generateProps(); + +// +// Finally code to create and return meta object +// + fprintf( out, " metaObj = QMetaObject::new_metaobject(\n" + "\t\"%s\", parentObject,\n", (const char*)qualifiedClassName() ); + + if ( g->slots.count() ) + fprintf( out, "\tslot_tbl, %d,\n", g->slots.count() ); + else + fprintf( out, "\t0, 0,\n" ); + + if ( g->signals.count() ) + fprintf( out, "\tsignal_tbl, %d,\n", g->signals.count() ); + else + fprintf( out, "\t0, 0,\n" ); + + fprintf( out, "#ifndef QT_NO_PROPERTIES\n" ); + if ( n_props ) + fprintf( out, "\tprops_tbl, %d,\n", n_props ); + else + fprintf( out, "\t0, 0,\n" ); + if ( n_enums ) + fprintf( out, "\tenum_tbl, %d,\n", n_enums ); + else + fprintf( out, "\t0, 0,\n" ); + fprintf( out, "#endif // QT_NO_PROPERTIES\n" ); + + if ( n_infos ) + fprintf( out, "\tclassinfo_tbl, %d );\n", n_infos ); + else + fprintf( out, "\t0, 0 );\n" ); + + +// +// Setup cleanup handler and return meta object +// + fprintf( out, " cleanUp_%s.setMetaObject( metaObj );\n", cleanup.data() ); + fprintf( out, " return metaObj;\n}\n" ); + +// +// End of function staticMetaObject() +// + +// +// Generate smart cast function +// + fprintf( out, "\nvoid* %s::qt_cast( const char* clname )\n{\n", + (const char*)qualifiedClassName() ); + fprintf( out, " if ( !qstrcmp( clname, \"%s\" ) )\n" + "\treturn this;\n", + (const char*)qualifiedClassName() ); + for ( const char* cname = g->multipleSuperClasses.first(); cname; cname = g->multipleSuperClasses.next() ) { + fprintf( out, " if ( !qstrcmp( clname, \"%s\" ) )\n", cname); + QCString fixed(cname); + while (fixed.find(">>") != -1) + fixed = fixed.replace(">>", "> >"); + fprintf( out, "\treturn (%s*)this;\n", fixed.data()); + } + if ( !g->superClassName.isEmpty() && !isQObject ) + fprintf( out, " return %s::qt_cast( clname );\n", + (const char*)purestSuperClassName() ); + else + fprintf( out, " return 0;\n" ); + fprintf( out, "}\n" ); + +// +// Generate internal signal functions +// + Function *f; + f = g->signals.first(); // make internal signal methods + static bool included_list_headers = FALSE; + int sigindex = 0; + while ( f ) { + QCString argstr; + char buf[12]; + Argument *a = f->args->first(); + int offset = 0; + const char *predef_call_func = 0; + bool hasReturnValue = f->type != "void" && (validUType( f->type ) || isVariantType( f->type) ); + if ( hasReturnValue ) { + ; // no predefined function available + } else if ( !a ) { + predef_call_func = "activate_signal"; + } else if ( f->args->count() == 1 ) { + QCString ctype = (a->leftType + ' ' + a->rightType).simplifyWhiteSpace(); + if ( !isInOut( ctype ) ) { + QCString utype = uType( ctype ); + if ( utype == "bool" ) + predef_call_func = "activate_signal_bool"; + else if ( utype == "QString" || utype == "int" || utype == "double" ) + predef_call_func = "activate_signal"; + } + } + + if ( !predef_call_func && !included_list_headers ) { + // yes we need it, because otherwise QT_VERSION may not be defined + fprintf( out, "\n#include <%sqobjectdefs.h>\n", (const char*)g->qtPath ); + fprintf( out, "#include <%sqsignalslotimp.h>\n", (const char*)g->qtPath ); + included_list_headers = TRUE; + } + + while ( a ) { // argument list + if ( !a->leftType.isEmpty() || !a->rightType.isEmpty() ) { + argstr += a->leftType; + argstr += " "; + sprintf( buf, "t%d", offset++ ); + argstr += buf; + argstr += a->rightType; + a = f->args->next(); + if ( a ) + argstr += ", "; + } else { + a = f->args->next(); + } + } + + fixRightAngles( &argstr ); + + fprintf( out, "\n// SIGNAL %s\n", (const char*)f->name ); + fprintf( out, "%s %s::%s(", (const char*) f->type, + (const char*)qualifiedClassName(), + (const char*)f->name ); + + if ( argstr.isEmpty() ) + fprintf( out, ")\n{\n" ); + else + fprintf( out, " %s )\n{\n", (const char*)argstr ); + + if ( predef_call_func ) { + fprintf( out, " %s( staticMetaObject()->signalOffset() + %d", predef_call_func, sigindex ); + if ( !argstr.isEmpty() ) + fprintf( out, ", t0" ); + fprintf( out, " );\n}\n" ); + } else { + if ( hasReturnValue ) + fprintf( out, " %s something;\n", f->type.data() ); + int nargs = f->args->count(); + fprintf( out, " if ( signalsBlocked() )\n\treturn%s;\n", hasReturnValue ? " something" : "" ); + fprintf( out, " QConnectionList *clist = receivers( staticMetaObject()->signalOffset() + %d );\n", + sigindex ); + fprintf( out, " if ( !clist )\n\treturn%s;\n", hasReturnValue ? " something" : "" ); + fprintf( out, " QUObject o[%d];\n", f->args->count() + 1 ); + + // initialize return value to something + if ( hasReturnValue ) { + if ( validUType( f->type ) ) { + QCString utype = uType( f->type ); + fprintf( out, " static_QUType_%s.set(o,something);\n", utype.data() ); + } else if ( uType( f->type ) == "varptr" ) { + fprintf( out, " static_QUType_varptr.set(o,&something);\n" ); + } else { + fprintf( out, " static_QUType_ptr.set(o,&something);\n" ); + } + } + + // initialize arguments + if ( !f->args->isEmpty() ) { + offset = 0; + Argument* a = f->args->first(); + while ( a ) { + QCString type = a->leftType + ' ' + a->rightType; + type = type.simplifyWhiteSpace(); + if ( validUType( type ) ) { + QCString utype = uType( type ); + fprintf( out, " static_QUType_%s.set(o+%d,t%d);\n", utype.data(), offset+1, offset ); + } else if ( uType( type ) == "varptr" ) { + fprintf( out, " static_QUType_varptr.set(o+%d,&t%d);\n", offset+1, offset ); + } else { + fprintf( out, " static_QUType_ptr.set(o+%d,&t%d);\n", offset+1, offset ); + } + a = f->args->next(); + offset++; + } + } + fprintf( out, " activate_signal( clist, o );\n" ); + + // get return values from inOut parameters + if ( !f->args->isEmpty() ) { + offset = 0; + Argument* a = f->args->first(); + while ( a ) { + QCString type = a->leftType + ' ' + a->rightType; + type = type.simplifyWhiteSpace(); + if ( validUType( type ) && isInOut( type ) ) { + QCString utype = uType( type ); + if ( utype == "enum" ) + fprintf( out, " t%d = (%s)static_QUType_%s.get(o+%d);\n", offset, type.data(), utype.data(), offset+1 ); + else if ( utype == "ptr" && type.right(2) == "**" ) + fprintf( out, " if (t%d) *t%d = *(%s)static_QUType_ptr.get(o+%d);\n", offset, offset, type.data(), offset+1 ); + else + fprintf( out, " t%d = static_QUType_%s.get(o+%d);\n", offset, utype.data(), offset+1 ); + } + a = f->args->next(); + offset++; + } + } + + // get and return return value + if ( hasReturnValue ) { + QCString utype = uType( f->type ); + if ( utype == "enum" || utype == "ptr" || utype == "varptr" ) // need cast + fprintf( out, " return (%s)static_QUType_%s.get(o);\n", f->type.data(), utype.data() ); + else + fprintf( out, " return static_QUType_%s.get(o);\n", utype.data() ); + } + + fprintf( out, "}\n" ); + } + + f = g->signals.next(); + sigindex++; + } + + +// +// Generate internal qt_invoke() function +// + fprintf( out, "\nbool %s::qt_invoke( int _id, QUObject* _o )\n{\n", qualifiedClassName().data() ); + + if( !g->slots.isEmpty() ) { + fprintf( out, " switch ( _id - staticMetaObject()->slotOffset() ) {\n" ); + int slotindex = -1; + for ( f = g->slots.first(); f; f = g->slots.next() ) { + slotindex ++; + if ( f->type == "void" && f->args->isEmpty() ) { + fprintf( out, " case %d: %s(); break;\n", slotindex, f->name.data() ); + continue; + } + + fprintf( out, " case %d: ", slotindex ); + bool hasReturnValue = FALSE; + bool hasVariantReturn = FALSE; + if ( f->type != "void" ) { + if ( validUType( f->type )) { + hasReturnValue = TRUE; + fprintf( out, "static_QUType_%s.set(_o,", uType(f->type).data() ); + } else if ( isVariantType( f->type ) ) { + hasReturnValue = hasVariantReturn = TRUE; + // do not need special handling for bool since this is handled as utype + fprintf( out, "static_QUType_QVariant.set(_o,QVariant(" ); + } + } + int offset = 0; + fprintf( out, "%s(", f->name.data() ); + Argument* a = f->args->first(); + while ( a ) { + QCString type = a->leftType + ' ' + a->rightType; + type = type.simplifyWhiteSpace(); + fixRightAngles( &type ); + if ( validUType( type ) ) { + QCString utype = uType( type ); + if ( utype == "ptr" || utype == "varptr" || utype == "enum" ) + fprintf( out, "(%s)static_QUType_%s.get(_o+%d)", type.data(), utype.data(), offset+1 ); + else + fprintf( out, "(%s)static_QUType_%s.get(_o+%d)", type.data(), utype.data(), offset+1 ); + } else { + QCString castType = castToUType( type ); + if(castType == type) + fprintf( out, "(%s)(*((%s*)static_QUType_ptr.get(_o+%d)))", type.data(), + castType.data(), offset+1 ); + else + fprintf( out, "(%s)*((%s*)static_QUType_ptr.get(_o+%d))", type.data(), + castType.data(), offset+1 ); + } + a = f->args->next(); + if ( a ) + fprintf( out, "," ); + offset++; + } + fprintf( out, ")" ); + if ( hasReturnValue ) + fprintf( out, ")" ); + if ( hasVariantReturn ) + fprintf( out, ")" ); + fprintf( out, "; break;\n" ); + } + fprintf( out, " default:\n" ); + + if ( !g->superClassName.isEmpty() && !isQObject ) { + fprintf( out, "\treturn %s::qt_invoke( _id, _o );\n", + (const char *) purestSuperClassName() ); + } else { + fprintf( out, "\treturn FALSE;\n" ); + } + fprintf( out, " }\n" ); + fprintf( out, " return TRUE;\n}\n" ); + } else { + if ( !g->superClassName.isEmpty() && !isQObject ) + fprintf( out, " return %s::qt_invoke(_id,_o);\n}\n", + (const char *) purestSuperClassName() ); + else + fprintf( out, " return FALSE;\n}\n" ); + } + + +// +// Generate internal qt_emit() function +// + fprintf( out, "\nbool %s::qt_emit( int _id, QUObject* _o )\n{\n", qualifiedClassName().data() ); + + if ( !g->signals.isEmpty() ) { + fprintf( out, " switch ( _id - staticMetaObject()->signalOffset() ) {\n" ); + int signalindex = -1; + for ( f = g->signals.first(); f; f = g->signals.next() ) { + signalindex++; + if ( f->type == "void" && f->args->isEmpty() ) { + fprintf( out, " case %d: %s(); break;\n", signalindex, f->name.data() ); + continue; + } + + fprintf( out, " case %d: ", signalindex ); + bool hasReturnValue = FALSE; + if ( f->type != "void" && validUType( f->type )) { + hasReturnValue = TRUE; + fprintf( out, "static_QUType_%s.set(_o,", uType(f->type).data() ); + } + int offset = 0; + fprintf( out, "%s(", f->name.data() ); + Argument* a = f->args->first(); + while ( a ) { + QCString type = a->leftType + ' ' + a->rightType; + type = type.simplifyWhiteSpace(); + fixRightAngles( &type ); + if ( validUType( type ) ) { + QCString utype = uType( type ); + if ( utype == "ptr" || utype == "varptr" || utype == "enum" ) + fprintf( out, "(%s)static_QUType_%s.get(_o+%d)", type.data(), utype.data(), offset+1 ); + else + fprintf( out, "(%s)static_QUType_%s.get(_o+%d)", type.data(), utype.data(), offset+1 ); + } else { + QCString castType = castToUType( type ); + if(castType == type) + fprintf( out, "(%s)(*((%s*)static_QUType_ptr.get(_o+%d)))", type.data(), + castType.data(), offset+1 ); + else + fprintf( out, "(%s)*((%s*)static_QUType_ptr.get(_o+%d))", type.data(), + castType.data(), offset+1 ); + } + a = f->args->next(); + if ( a ) + fprintf( out, "," ); + offset++; + } + fprintf( out, ")" ); + if ( hasReturnValue ) + fprintf( out, ")" ); + fprintf( out, "; break;\n" ); + } + fprintf( out, " default:\n" ); + if ( !g->superClassName.isEmpty() && !isQObject ) + fprintf( out, "\treturn %s::qt_emit(_id,_o);\n", + (const char *) purestSuperClassName() ); + else + fprintf( out, "\treturn FALSE;\n" ); + fprintf( out, " }\n" ); + fprintf( out, " return TRUE;\n}\n" ); + } else { + if ( !g->superClassName.isEmpty() && !isQObject ) + fprintf( out, " return %s::qt_emit(_id,_o);\n}\n", + (const char *) purestSuperClassName() ); + else + fprintf( out, " return FALSE;\n}\n" ); + } + + + fprintf( out, "#ifndef QT_NO_PROPERTIES\n" ); +// +// Generate internal qt_property() functions +// + + fprintf( out, "\nbool %s::qt_property( int id, int f, QVariant* v)\n{\n", qualifiedClassName().data() ); + + if ( !g->props.isEmpty() ) { + fprintf( out, " switch ( id - staticMetaObject()->propertyOffset() ) {\n" ); + int propindex = -1; + bool need_resolve = FALSE; + + for( QPtrListIterator it( g->props ); it.current(); ++it ){ + propindex ++; + fprintf( out, " case %d: ", propindex ); + fprintf( out, "switch( f ) {\n" ); + + uint flag_break = 0; + uint flag_propagate = 0; + + if ( it.current()->setfunc ) { + fprintf( out, "\tcase 0: %s(", it.current()->setfunc->name.data() ); + QCString type = it.current()->type.copy(); // detach on purpose + if ( it.current()->oredEnum ) + type = it.current()->enumsettype; + if ( type == "uint" ) + fprintf( out, "v->asUInt()" ); + else if ( type == "unsigned int" ) + fprintf( out, "(uint)v->asUInt()" ); + else if ( type == "QMap" ) + fprintf( out, "v->asMap()" ); + else if ( type == "QValueList" ) + fprintf( out, "v->asList()" ); + else if ( type == "Q_LLONG" ) + fprintf( out, "v->asLongLong()" ); + else if ( type == "Q_ULLONG" ) + fprintf( out, "v->asULongLong()" ); + else if ( isVariantType( type ) ) { + if ( type[0] == 'Q' ) + type = type.mid(1); + else + type[0] = toupper( type[0] ); + fprintf( out, "v->as%s()", type.data() ); + } else { + fprintf( out, "(%s&)v->asInt()", type.data() ); + } + fprintf( out, "); break;\n" ); + + } else if ( it.current()->override ) { + flag_propagate |= 1 << (0+1); + } + if ( it.current()->getfunc ) { + if ( it.current()->gspec == Property::Pointer ) + fprintf( out, "\tcase 1: if ( this->%s() ) *v = QVariant( %s*%s()%s ); break;\n", + it.current()->getfunc->name.data(), + !isVariantType( it.current()->type ) ? "(int)" : "", + it.current()->getfunc->name.data(), + it.current()->type == "bool" ? ", 0" : "" ); + else + fprintf( out, "\tcase 1: *v = QVariant( %sthis->%s()%s ); break;\n", + !isVariantType( it.current()->type ) ? "(int)" : "", + it.current()->getfunc->name.data(), + it.current()->type == "bool" ? ", 0" : "" ); + } else if ( it.current()->override ) { + flag_propagate |= 1<< (1+1); + } + + if ( !it.current()->reset.isEmpty() ) + fprintf( out, "\tcase 2: this->%s(); break;\n", it.current()->reset.data() ); + + if ( it.current()->designable.isEmpty() ) + flag_propagate |= 1 << (3+1); + else if ( it.current()->designable == "true" ) + flag_break |= 1 << (3+1); + else if ( it.current()->designable != "false" ) + fprintf( out, "\tcase 3: return this->%s();\n", it.current()->designable.data() ); + + if ( it.current()->scriptable.isEmpty() ) + flag_propagate |= 1 << (4+1); + else if ( it.current()->scriptable == "true" ) + flag_break |= 1 << (4+1); + else if ( it.current()->scriptable != "false" ) + fprintf( out, "\tcase 4: return this->%s();\n", it.current()->scriptable.data() ); + + if ( it.current()->stored.isEmpty() ) + flag_propagate |= 1 << (5+1); + else if ( it.current()->stored == "true" ) + flag_break |= 1 << (5+1); + else if ( it.current()->stored != "false" ) + fprintf( out, "\tcase 5: return this->%s();\n", it.current()->stored.data() ); + + int i = 0; + if ( flag_propagate != 0 ) { + fprintf( out, "\t" ); + for ( i = 0; i <= 5; i++ ) { + if ( flag_propagate & (1 << (i+1) ) ) + fprintf( out, "case %d: ", i ); + } + if (!g->superClassName.isEmpty() && !isQObject ) { + fprintf( out, "goto resolve;\n" ); + need_resolve = TRUE; + } else { + fprintf( out, " return FALSE;\n" ); + } + } + if ( flag_break != 0 ) { + fprintf( out, "\t" ); + for ( i = 0; i <= 5; i++ ) { + if ( flag_break & (1 << (i+1) ) ) + fprintf( out, "case %d: ", i ); + } + fprintf( out, "break;\n"); + } + + fprintf( out, "\tdefault: return FALSE;\n } break;\n" ); + } + fprintf( out, " default:\n" ); + if ( !g->superClassName.isEmpty() && !isQObject ) + fprintf( out, "\treturn %s::qt_property( id, f, v );\n", + (const char *) purestSuperClassName() ); + else + fprintf( out, "\treturn FALSE;\n" ); + fprintf( out, " }\n" ); + fprintf( out, " return TRUE;\n" ); + + if ( need_resolve ) + fprintf( out, "resolve:\n return %s::qt_property( staticMetaObject()->resolveProperty(id), f, v );\n", + (const char *) purestSuperClassName() ); + fprintf( out, "}\n" ); + } else { + if ( !g->superClassName.isEmpty() && !isQObject ) + fprintf( out, " return %s::qt_property( id, f, v);\n}\n", + (const char *) purestSuperClassName() ); + else + fprintf( out, " return FALSE;\n}\n" ); + } + + fprintf( out, "\nbool %s::qt_static_property( QObject* , int , int , QVariant* ){ return FALSE; }\n", qualifiedClassName().data() ); + fprintf( out, "#endif // QT_NO_PROPERTIES\n" ); +} + + +ArgList *addArg( Argument *a ) // add argument to list +{ + if ( (!a->leftType.isEmpty() || !a->rightType.isEmpty() ) ) //filter out truely void arguments + tmpArgList->append( a ); + return tmpArgList; +} + +void addEnum() +{ + // Avoid duplicates + for( QPtrListIterator lit( g->enums ); lit.current(); ++lit ) { + if ( lit.current()->name == tmpEnum->name ) + { + if ( displayWarnings ) + moc_err( "Enum %s defined twice.", (const char*)tmpEnum->name ); + } + } + + // Only look at types mentioned in Q_ENUMS and Q_SETS + if ( g->qtEnums.contains( tmpEnum->name ) || g->qtSets.contains( tmpEnum->name ) ) + { + g->enums.append( tmpEnum ); + if ( g->qtSets.contains( tmpEnum->name ) ) + tmpEnum->set = TRUE; + else + tmpEnum->set = FALSE; + } + else + delete tmpEnum; + tmpEnum = new Enum; +} + +void addMember( Member m ) +{ + if ( skipFunc ) { + tmpFunc->args = tmpArgList; // just to be sure + delete tmpFunc; + tmpArgList = new ArgList; // ugly but works + tmpFunc = new Function; + skipFunc = FALSE; + return; + } + + tmpFunc->type = tmpFunc->type.simplifyWhiteSpace(); + tmpFunc->access = tmpAccess; + tmpFunc->args = tmpArgList; + tmpFunc->lineNo = lineNo; + + for ( ;; ) { + g->funcs.append( tmpFunc ); + + if ( m == SignalMember ) { + g->signals.append( tmpFunc ); + break; + } else { + if ( m == SlotMember ) + g->slots.append( tmpFunc ); + // PropertyCandidateMember or SlotMember + if ( !tmpFunc->name.isEmpty() && tmpFunc->access == Public ) + g->propfuncs.append( tmpFunc ); + if ( !tmpFunc->args || !tmpFunc->args->hasDefaultArguments() ) + break; + tmpFunc = new Function( *tmpFunc ); + tmpFunc->args = tmpFunc->args->magicClone(); + } + } + + skipFunc = FALSE; + tmpFunc = new Function; + tmpArgList = new ArgList; +} + +void checkPropertyName( const char* ident ) +{ + if ( ident[0] == '_' ) { + moc_err( "Invalid property name '%s'.", ident ); + return; + } +} -- cgit v1.2.1