From 4088d90d9abafaa51250e55a5f48a787a921ed98 Mon Sep 17 00:00:00 2001
From: dimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7>
Date: Tue, 13 Apr 2004 19:01:22 +0000
Subject: Release-1.3.6-20040413

---
 INSTALL                   |   4 +-
 README                    |   4 +-
 VERSION                   |   2 +-
 doc/commands.doc          |  10 +
 doc/config.doc            |  29 ++-
 doc/language.doc          |   2 +-
 packages/rpm/doxygen.spec |   2 +-
 src/classdef.cpp          |  64 +++++-
 src/classdef.h            |   8 +
 src/classlist.cpp         |  22 +-
 src/cmdmapper.cpp         |   1 +
 src/cmdmapper.h           |   3 +-
 src/code.l                | 570 +++++++++++++++++++++++++++++++++++++++++++---
 src/compound.xsd          |   2 +
 src/compound_xsd.h        |   2 +
 src/config.l              |  98 +++++---
 src/docparser.cpp         |   5 +
 src/docparser.h           |   2 +-
 src/doxygen.cpp           |  38 ++--
 src/entry.h               |   3 +-
 src/filedef.cpp           |   2 +-
 src/htmldocvisitor.cpp    |  22 +-
 src/htmlgen.cpp           |  38 +++-
 src/htmlgen.h             |   4 +-
 src/index.cpp             |   2 +-
 src/latexdocvisitor.cpp   |  11 +-
 src/mandocvisitor.cpp     |  14 ++
 src/memberlist.cpp        |   4 +-
 src/perlmodgen.cpp        |  12 +
 src/pre.l                 |   4 +-
 src/printdocvisitor.h     |   1 +
 src/rtfdocvisitor.cpp     |  15 +-
 src/scanner.l             | 114 ++++++----
 src/tagreader.cpp         |   2 +
 src/translator_hu.h       |  28 ++-
 src/util.cpp              |  63 +++--
 src/util.h                |   3 +-
 src/xmldocvisitor.cpp     |  10 +
 src/xmlgen.cpp            |   9 +
 39 files changed, 1021 insertions(+), 208 deletions(-)

diff --git a/INSTALL b/INSTALL
index 78d83e1..62e0e4c 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,7 +1,7 @@
-DOXYGEN Version 1.3.6-20040324
+DOXYGEN Version 1.3.6-20040413
 
 Please read the installation section of the manual 
 (http://www.doxygen.org/install.html) for instructions.
 
 --------
-Dimitri van Heesch (24 March 2004)
+Dimitri van Heesch (13 April 2004)
diff --git a/README b/README
index 8f59530..b57a95f 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-DOXYGEN Version 1.3.6_20040324
+DOXYGEN Version 1.3.6_20040413
 
 Please read INSTALL for compilation instructions.
 
@@ -17,4 +17,4 @@ to subscribe to the lists or to visit the archives.
 
 Enjoy,
 
-Dimitri van Heesch (dimitri@stack.nl) (24 March 2004)
+Dimitri van Heesch (dimitri@stack.nl) (13 April 2004)
diff --git a/VERSION b/VERSION
index 2836576..8e7c0ce 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.3.6-20040324
+1.3.6-20040413
diff --git a/doc/commands.doc b/doc/commands.doc
index 39a6aa6..a7baae6 100644
--- a/doc/commands.doc
+++ b/doc/commands.doc
@@ -86,6 +86,7 @@ documentation:
 \refitem cmdifnot \\ifnot
 \refitem cmdimage \\image
 \refitem cmdinclude \\include
+\refitem cmdincludelineno \\includelineno
 \refitem cmdingroup \\ingroup
 \refitem cmdinternal \\internal
 \refitem cmdinvariant \\invariant
@@ -1309,6 +1310,15 @@ ALIASES  = "english=\if english" \
   \sa section \ref cmdexample "\\example" and \ref cmddontinclude "\\dontinclude".
 
 <hr>
+\section cmdincludelineno \includelineno <file-name>
+
+  \addindex \\includelineno
+  This command works the same way as \\include, but will add line 
+  numbers to the included file.
+
+  \sa section \ref cmdinclude "\\include".
+
+<hr>
 \section cmdline \line ( pattern )
 
   \addindex \\line
diff --git a/doc/config.doc b/doc/config.doc
index 35aa62b..8c595a5 100644
--- a/doc/config.doc
+++ b/doc/config.doc
@@ -188,6 +188,7 @@ followed by the descriptions of the tags grouped by category.
 \refitem cfg_sort_member_docs SORT_MEMBER_DOCS
 \refitem cfg_source_browser SOURCE_BROWSER
 \refitem cfg_strip_code_comments STRIP_CODE_COMMENTS
+\refitem cfg_strip_from_inc_path STRIP_FROM_INC_PATH
 \refitem cfg_strip_from_path STRIP_FROM_PATH
 \refitem cfg_subgrouping SUBGROUPING
 \refitem cfg_tab_size TAB_SIZE
@@ -326,16 +327,30 @@ followed by the descriptions of the tags grouped by category.
  If the \c FULL_PATH_NAMES tag is set to \c YES then the \c STRIP_FROM_PATH tag
  can be used to strip a user-defined part of the path. Stripping is
  only done if one of the specified strings matches the left-hand part of the 
- path.
+ path. The tag can be used to show relative paths in the file list.
+ If left blank the directory from which doxygen is run is used as the
+ path to strip.
+
+\anchor cfg_strip_from_inc_path
+<dt>\c STRIP_FROM_INC_PATH
+ The \c STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+ the path mentioned in the documentation of a class, which tells
+ the reader which header file to include in order to use a class. 
+ If left blank only the name of the header file containing the class
+ definition is used. Otherwise one should specify the include paths that 
+ are normally passed to the compiler using the -I flag.
+
+
 
 \anchor cfg_case_sense_names
 <dt>\c CASE_SENSE_NAMES <dd>
  \addindex CASE_SENSE_NAMES
- If the \c CASE_SENSE_NAMES tag is set to \c NO (the default) then doxygen
+ If the \c CASE_SENSE_NAMES tag is set to \c NO then doxygen
  will only generate file names in lower-case letters. If set to
  \c YES upper-case letters are also allowed. This is useful if you have
  classes or files whose names only differ in case and if your file system
- supports case sensitive file names.
+ supports case sensitive file names. Windows users are advised to set this
+ option to NO.
 
 \anchor cfg_short_names
 <dt>\c SHORT_NAMES <dd>
@@ -888,12 +903,16 @@ function's detailed documentation block.
 
  The following commands have a special meaning inside the header:
  <code>\$title</code>, <code>\$datetime</code>, <code>\$date</code>,
- <code>\$doxygenversion</code>, <code>\$projectname</code>, 
+ <code>\$doxygenversion</code>, <code>\$projectname</code>, and
  <code>\$projectnumber</code>. 
  Doxygen will replace them by respectively 
  the title of the page, the current date and time, only the current date,
  the version number of doxygen, the project name (see \c PROJECT_NAME), or the
- project number (see \c PROJECT_NUMBER).
+ project number (see \c PROJECT_NUMBER). 
+
+ If \c CREATE_SUBDIRS is enabled, the command <code>\$relpath\$</code> can be 
+ used to produce a relative path to the root of the HTML output directory,
+ e.g. use \$relpath\$doxygen.css, to refer to the standard style sheet.
    
  See also section \ref doxygen_usage for information on how to generate
  the default header that doxygen normally uses.
diff --git a/doc/language.doc b/doc/language.doc
index fb25b1b..839ffbe 100644
--- a/doc/language.doc
+++ b/doc/language.doc
@@ -23,7 +23,7 @@ text fragments, generated by doxygen, can be produced in languages other
 than English (the default). The output language is chosen through the
 configuration file (with default name and known as Doxyfile).
 
-Currently (version 1.3.6-20040222), 28 languages 
+Currently (version 1.3.6-20040413), 28 languages 
 are supported (sorted alphabetically):
 Brazilian Portuguese, Catalan, Chinese, Chinese Traditional, Croatian,
 Czech, Danish, Dutch, English, Finnish, French, German, Greek,
diff --git a/packages/rpm/doxygen.spec b/packages/rpm/doxygen.spec
index f6465d0..0bf97b8 100644
--- a/packages/rpm/doxygen.spec
+++ b/packages/rpm/doxygen.spec
@@ -1,6 +1,6 @@
 Summary: A documentation system for C/C++.
 Name: doxygen
-Version: 1.3.6_20040324
+Version: 1.3.6_20040413
 Release: 1
 Epoch: 1
 Source0: ftp://ftp.stack.nl/pub/users/dimitri/%{name}-%{version}.src.tar.gz
diff --git a/src/classdef.cpp b/src/classdef.cpp
index 802b9cd..0ba7b6e 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -93,6 +93,7 @@ ClassDef::ClassDef(
   m_isStatic = FALSE;
   m_isObjC = FALSE;
   m_membersMerged = FALSE;
+  m_categoryOf = 0;
   QCString ns;
   extractNamespaceName(m_name,m_className,ns);
   //printf("m_name=%s m_className=%s ns=%s\n",m_name.data(),m_className.data(),ns.data());
@@ -141,6 +142,10 @@ QCString ClassDef::displayName() const
   {
     n=substitute(n,"::",".");
   }
+  if (m_compType==ClassDef::Protocol && n.right(2)=="-p")
+  {
+    n="< "+n.left(n.length()-2)+" >";
+  }
   return n;
 }
 
@@ -2044,7 +2049,7 @@ void ClassDef::mergeMembers()
               //printf("same member found srcMi->virt=%d dstMi->virt=%d\n",srcMi->virt,dstMi->virt);
               if ((srcMi->virt!=Normal && dstMi->virt!=Normal) ||
                   bClass->name()+"::"+srcMi->scopePath == dstMi->scopePath ||
-                  dstMd->getClassDef()->compoundType()==ClassDef::Interface
+                  dstMd->getClassDef()->compoundType()==Interface
                  ) 
               {
                 found=TRUE;
@@ -2184,6 +2189,52 @@ void ClassDef::mergeMembers()
 
 //----------------------------------------------------------------------------
 
+/*! Merges the members of a Objective-C category into this class.
+ */
+void ClassDef::mergeCategory(ClassDef *category)
+{
+  category->m_categoryOf = this;
+    
+  MemberNameInfoSDict *srcMnd  = category->m_allMemberNameInfoSDict;
+  MemberNameInfoSDict *dstMnd  =           m_allMemberNameInfoSDict;
+
+  MemberNameInfoSDict::Iterator srcMnili(*srcMnd);
+  MemberNameInfo *srcMni;
+  for ( ; (srcMni=srcMnili.current()) ; ++srcMnili)
+  {
+    MemberNameInfo *dstMni=dstMnd->find(srcMni->memberName());
+    if (dstMni) // method is already defined in the class
+    {
+      // TODO: we should remove the other member and insert this one.
+    }
+    else // new method name
+    {
+      // create a deep copy of the list (only the MemberInfo's will be 
+      // copied, not the actual MemberDef's)
+      MemberNameInfo *newMni = 0;
+      newMni = new MemberNameInfo(srcMni->memberName()); 
+
+      // copy the member(s) from the category to this class
+      MemberNameInfoIterator mnii(*srcMni);
+      MemberInfo *mi;
+      for (;(mi=mnii.current());++mnii)
+      {
+        //printf("Adding!\n");
+        MemberInfo *newMi=new MemberInfo(mi->memberDef,mi->prot,mi->virt,mi->inherited);
+        newMi->scopePath=mi->scopePath;
+        newMi->ambigClass=mi->ambigClass;
+        newMi->ambiguityResolutionScope=mi->ambiguityResolutionScope.copy();
+        newMni->append(newMi);
+      }
+
+      // add it to the dictionary
+      dstMnd->append(newMni->memberName(),newMni);
+    }
+  }
+}
+
+//----------------------------------------------------------------------------
+
 void ClassDef::addUsedClass(ClassDef *cd,const char *accessName)
 {
   if (m_usesImplClassDict==0) 
@@ -2418,13 +2469,9 @@ void ClassDef::determineIntfUsageRelation()
 }
 #endif
 
-//PackageDef *ClassDef::packageDef() const
-//{
-//  return m_fileDef ? m_fileDef->packageDef() : 0;
-//}
-
 QCString ClassDef::compoundTypeString() const
 {
+  if (m_compType==Interface && m_isObjC) return "class";
   switch (m_compType)
   {
     case Class:     return "class";
@@ -2773,7 +2820,6 @@ MemberDef *ClassDef::getMemberByName(const QCString &name)
 {
   MemberDef *xmd = 0;
   MemberNameInfo *mni = m_allMemberNameInfoSDict->find(name);
-  //printf("getMemberByName(%s)=%p\n",name.data(),mni);
   if (mni)
   {
     const int maxInheritanceDepth = 100000;
@@ -2783,8 +2829,9 @@ MemberDef *ClassDef::getMemberByName(const QCString &name)
     for (mnii.toFirst();(mi=mnii.current());++mnii)
     {
       ClassDef *mcd=mi->memberDef->getClassDef();
-      //printf("found member in %s\n",mcd->name().data());
       int m=minClassDistance(this,mcd);
+      //printf("found member in %s linkable=%d m=%d\n",
+      //    mcd->name().data(),mcd->isLinkable(),m);
       if (m<mdist && mcd->isLinkable())
       {
         mdist=m;
@@ -2792,6 +2839,7 @@ MemberDef *ClassDef::getMemberByName(const QCString &name)
       }
     }
   }
+  //printf("getMemberByName(%s)=%p\n",name.data(),xmd);
   return xmd;
 }
 
diff --git a/src/classdef.h b/src/classdef.h
index fb7dd88..d745f83 100644
--- a/src/classdef.h
+++ b/src/classdef.h
@@ -202,6 +202,8 @@ class ClassDef : public Definition
     /*! Returns TRUE if this class is implemented in Objective-C */
     bool isObjectiveC() const { return m_isObjC; }
 
+    ClassDef *categoryOf() const { return m_categoryOf; }
+
     /*! returns the name of the class including outer classes, but not
      *  including namespaces.
      */
@@ -273,6 +275,7 @@ class ClassDef : public Definition
     void setNamespace(NamespaceDef *nd) { m_nspace = nd; }
     void setTemplateArguments(ArgumentList *al);
     void mergeMembers();
+    void mergeCategory(ClassDef *category);
     void setFileDef(FileDef *fd) { m_fileDef=fd; }
     //void determineImplUsageRelation();
     //void determineIntfUsageRelation();
@@ -442,6 +445,11 @@ class ClassDef : public Definition
 
     /*! class name with outer class scope, but without namespace scope. */
     QCString m_className;
+
+    /*! If this class is a Objective-C category, then this points to the
+     *  class which is extended.
+     */
+    ClassDef *m_categoryOf;
 };
 
 /*! \brief Class that contains information about a usage relation. 
diff --git a/src/classlist.cpp b/src/classlist.cpp
index 7a52556..d538cbb 100644
--- a/src/classlist.cpp
+++ b/src/classlist.cpp
@@ -102,15 +102,15 @@ void ClassSDict::writeDeclaration(OutputList &ol,const ClassDef::CompoundType *f
           }
           ol.startMemberItem(FALSE);
           QCString tmp = cd->compoundTypeString();
-          QCString cname;
-          if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
-          {
-            cname = substitute(cd->className(),"::",".");
-          }
-          else
-          {
-            cname = cd->className();
-          }
+          QCString cname = cd->displayName();
+          //if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
+          //{
+          //  cname = substitute(cd->className(),"::",".");
+          //}
+          //else
+          //{
+          //  cname = cd->className();
+          //}
           ol.writeString(tmp);
           ol.writeString(" ");
           ol.insertMemberAlign();
@@ -141,12 +141,12 @@ void ClassSDict::writeDeclaration(OutputList &ol,const ClassDef::CompoundType *f
             {
               ol.pushGeneratorState();
               ol.disableAllBut(OutputGenerator::Html);
-              ol.endEmphasis();
+              //ol.endEmphasis();
               ol.docify(" ");
               ol.startTextLink(cd->getOutputFileBase(),"_details");
               ol.parseText(theTranslator->trMore());
               ol.endTextLink();
-              ol.startEmphasis();
+              //ol.startEmphasis();
               ol.popGeneratorState();
             }
             ol.endMemberDescription();
diff --git a/src/cmdmapper.cpp b/src/cmdmapper.cpp
index 959be75..b3047e2 100644
--- a/src/cmdmapper.cpp
+++ b/src/cmdmapper.cpp
@@ -105,6 +105,7 @@ CommandMap cmdMap[] =
   { "enddot",        CMD_ENDDOT },
   { "manonly",       CMD_MANONLY },
   { "endmanonly",    CMD_ENDMANONLY },
+  { "includelineno", CMD_INCWITHLINES },
   { 0,               0 }
 };
 
diff --git a/src/cmdmapper.h b/src/cmdmapper.h
index 18e43e3..a68d2bc 100644
--- a/src/cmdmapper.h
+++ b/src/cmdmapper.h
@@ -105,7 +105,8 @@ enum CommandType
   CMD_DOT          = 71,
   CMD_ENDDOT       = 72,
   CMD_MANONLY      = 73,
-  CMD_ENDMANONLY   = 74
+  CMD_ENDMANONLY   = 74,
+  CMD_INCWITHLINES = 75
 };
 
 enum HtmlTagType
diff --git a/src/code.l b/src/code.l
index d0b7058..5bf9935 100644
--- a/src/code.l
+++ b/src/code.l
@@ -53,7 +53,6 @@
 static BaseCodeDocInterface * g_code;
 
 static ClassSDict    g_codeClassSDict(17);
-//static ClassDef     *g_curClassDef;
 static QCString      g_curClassName;
 static QStrList      g_curClassBases;
 
@@ -104,6 +103,35 @@ static int           g_memCallContext;
 static int	     g_lastCContext;
 
 static bool          g_insideObjC;
+static bool          g_insideProtocolList;
+
+// context for an Objective-C method call
+struct ObjCCallCtx
+{
+  int id;
+  QCString methodName;
+  QCString objectTypeOrName;
+  ClassDef *objectType;
+  MemberDef *objectVar;
+  MemberDef *method;
+  QCString format;
+  int lexState;
+  int braceCount;
+};
+
+// globals for objective-C method calls 
+static ObjCCallCtx *g_currentCtx=0;
+static int g_currentCtxId=0;
+static int g_currentNameId=0;
+static int g_currentObjId=0;
+static QStack<ObjCCallCtx> g_contextStack;
+static QIntDict<ObjCCallCtx> g_contextDict;
+static QIntDict<QCString> g_nameDict;
+static QIntDict<QCString> g_objectDict;
+static int g_braceCount=0;
+  
+static void saveObjCContext();
+static void restoreObjCContext();
 
 //-------------------------------------------------------------------
 
@@ -184,7 +212,8 @@ void VariableContext::addVariable(const QCString &type,const QCString &name)
     ltype = ltype.right(ltype.length()-6);
   }
   if (ltype.isEmpty() || lname.isEmpty()) return;
-  DBG_CTX((stderr,"** AddVariable trying: type=%s name=%s\n",ltype.data(),lname.data()));
+  DBG_CTX((stderr,"** addVariable trying: type=%s name=%s g_currentDefinition=%s\n",
+	ltype.data(),lname.data(),g_currentDefinition?g_currentDefinition->name().data():"<none>"));
   Scope *scope = m_scopes.count()==0 ? &m_globalScope : m_scopes.getLast();
   ClassDef *varType;
   int i=0;
@@ -193,17 +222,17 @@ void VariableContext::addVariable(const QCString &type,const QCString &name)
       (varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,ltype)) // look for global class definitions
      ) 
   {
-    DBG_CTX((stderr,"** AddVariable type=%s name=%s\n",ltype.data(),lname.data()));
+    DBG_CTX((stderr,"** addVariable type=%s name=%s\n",ltype.data(),lname.data()));
     scope->append(lname,varType); // add it to a list
   }
   else if ((i=ltype.find('<'))!=-1)
   {
-    // probably a template class, try without arguments as well
+    // probably a template class, try without template arguments as well
     addVariable(ltype.left(i),name);
   }
-  else // add a dummy entry so the name is hidden
+  else // add a dummy entry so the name is hidden to avoid false links
   {
-    //printf("adding dummy context!\n");
+    DBG_CTX((stderr,"** addVariable: dummy context\n"));
     scope->append(lname,dummyContext);
   }
 }
@@ -567,7 +596,7 @@ static ClassDef *stripClassName(const char *s)
 static MemberDef *setCallContextForVar(const QCString &name)
 {
   if (name.isEmpty()) return 0;
-  //printf("setCallContextForVar(%s) g_classScope=%s\n",name.data(),g_classScope.data());
+  //fprintf(stderr,"setCallContextForVar(%s) g_classScope=%s\n",name.data(),g_classScope.data());
 
   int scopeEnd = name.findRev("::");
   if (scopeEnd!=-1) // name with explicit scope
@@ -592,10 +621,10 @@ static MemberDef *setCallContextForVar(const QCString &name)
   ClassDef *mcd = g_theVarContext.findVariable(name);
   if (mcd) // local variable
   {
-    //printf("local variable\n");
+    //fprintf(stderr,"local variable\n");
     if (mcd!=VariableContext::dummyContext)
     {
-      //printf("local var `%s' mcd=%s\n",name.data(),mcd->name().data());
+      //fprintf(stderr,"local var `%s' mcd=%s\n",name.data(),mcd->name().data());
       g_theCallContext.setClass(mcd);
     }
   }
@@ -605,12 +634,14 @@ static MemberDef *setCallContextForVar(const QCString &name)
     mcd = getClass(g_classScope);
     if (mcd)
     {
+      //fprintf(stderr,"Inside class %s\n",mcd->name().data());
       MemberDef *md=mcd->getMemberByName(name);
       if (md) 
       {
+        //fprintf(stderr,"Found member %s\n",md->name().data());
 	if (g_scopeStack.top()!=CLASSBLOCK)
 	{
-          //printf("class member `%s' mcd=%s\n",name.data(),mcd->name().data());
+          //fprintf(stderr,"class member `%s' mcd=%s\n",name.data(),mcd->name().data());
 	  g_theCallContext.setClass(stripClassName(md->typeString()));
 	}
 	return md;
@@ -680,7 +711,7 @@ static void generateClassOrGlobalLink(BaseCodeDocInterface &ol,char *clName,
                                       bool typeOnly=FALSE)
 {
   int i=0;
-  //printf("generateClassOrGlobalLink(clName=%s)\n",clName);
+  //fprintf(stderr,"generateClassOrGlobalLink(clName=%s)\n",clName);
   if (*clName=='~') // correct for matching negated values i.s.o. destructors.
   {
     g_code->codify("~");
@@ -688,6 +719,10 @@ static void generateClassOrGlobalLink(BaseCodeDocInterface &ol,char *clName,
   }
   QCString className=clName;
   if (className.isEmpty()) return;
+  if (g_insideProtocolList)
+  {
+    className+="-p";
+  }
   ClassDef *cd=0;
   MemberDef *md=0;
 
@@ -715,7 +750,7 @@ static void generateClassOrGlobalLink(BaseCodeDocInterface &ol,char *clName,
 	g_anchorCount++;
       }
     }
-    writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),0,className);
+    writeMultiLineCodeLink(ol,cd->getReference(),cd->getOutputFileBase(),0,clName);
     addToSearchIndex(className);
     if (md)
     {
@@ -728,7 +763,7 @@ static void generateClassOrGlobalLink(BaseCodeDocInterface &ol,char *clName,
       }
     }
   }
-  else 
+  else // not a class, maybe a global member
   {
     //printf("class %s not linkable! cd=%p md=%p typeOnly=%d\n",clName,cd,md,typeOnly);
     if (md!=0 || (cd==0 && !typeOnly)) // not a class, see if it is a global enum/variable/typedef.
@@ -736,7 +771,15 @@ static void generateClassOrGlobalLink(BaseCodeDocInterface &ol,char *clName,
       if (md==0) // not found as a typedef
       {
 	md = setCallContextForVar(clName);
-        if (md && g_currentDefinition!=0 && 
+	if (md && g_currentDefinition)
+	{
+	  //fprintf(stderr,"%s accessible from %s? %d md->getOuterScope=%s\n",
+	  //    md->name().data(),g_currentDefinition->name().data(),
+	  //    isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md),
+	  //    md->getOuterScope()->name().data());
+	}
+	     
+        if (md && g_currentDefinition && 
 	    isAccessibleFrom(g_currentDefinition,g_sourceFileDef,md)==-1)
 	{
 	  md=0; // variable not accessible
@@ -762,6 +805,7 @@ static void generateClassOrGlobalLink(BaseCodeDocInterface &ol,char *clName,
       }
     }
     
+    // nothing found, just write out the word
     codifyLines(clName);
     addToSearchIndex(clName);
   }
@@ -1055,8 +1099,313 @@ static void startFontClass(const char *s)
   g_currentFontClass=s;
 }
 
+//----------------------------------------------------------------------------
+
+// recursively writes a linkified Objective-C method call
+static void writeObjCMethodCall(ObjCCallCtx *ctx)
+{
+  if (ctx==0) return;
+  const char *p = ctx->format.data();
+  //printf("writeObjCMethodCall(%s) obj=%s method=%s\n",
+  //    ctx->format.data(),ctx->objectTypeOrName.data(),ctx->methodName.data());
+  char c;
+  if (!ctx->objectTypeOrName.isEmpty() && ctx->objectTypeOrName.at(0)!='$')
+  {
+    //printf("Looking for object=%s method=%s\n",ctx->objectTypeOrName.data(),
+    //	ctx->methodName.data());
+    ClassDef *cd = g_theVarContext.findVariable(ctx->objectTypeOrName);
+    if (cd==0) // not a local variable
+    {
+      if (ctx->objectTypeOrName=="self")
+      {
+	if (g_currentDefinition && 
+	    g_currentDefinition->definitionType()==Definition::TypeClass)
+	{
+	  ctx->objectType = (ClassDef *)g_currentDefinition;
+	}
+      }
+      else
+      {
+        ctx->objectType = getResolvedClass(
+  	  g_currentDefinition,
+	  g_sourceFileDef,
+	  ctx->objectTypeOrName,
+	  &ctx->method);
+      }
+      //printf("  object is class? %p\n",ctx->objectType);
+      if (ctx->objectType) // found class
+      {
+	ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
+        //printf("    yes->method=%s\n",ctx->method?ctx->method->name().data():"<none>");
+      }
+      else if (ctx->method==0) // search for class variable with the same name
+      {
+        //printf("    no\n");
+	//printf("g_currentDefinition=%p\n",g_currentDefinition);
+	if (g_currentDefinition && 
+	    g_currentDefinition->definitionType()==Definition::TypeClass)
+	{
+	  ctx->objectVar = ((ClassDef *)g_currentDefinition)->getMemberByName(ctx->objectTypeOrName);
+	  //printf("      ctx->objectVar=%p\n",ctx->objectVar);
+	  if (ctx->objectVar)
+	  {
+	    ctx->objectType = stripClassName(ctx->objectVar->typeString());
+	    //printf("        ctx->objectType=%p\n",ctx->objectType);
+	    if (ctx->objectType)
+	    {
+	      ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
+	      //printf("          ctx->method=%p\n",ctx->method);
+	    }
+	  }
+	}
+      }
+    }
+    else // local variable
+    {
+      //printf("  object is local variable\n");
+      if (cd!=VariableContext::dummyContext)
+      {
+        ctx->method = cd->getMemberByName(ctx->methodName);
+        //printf("   class=%p method=%p\n",cd,ctx->method);
+      }
+    }
+  }
+
+  //printf("[");
+  while ((c=*p++)) // for each character in ctx->format
+  {
+    if (c=='$')
+    {
+      char nc=*p++;
+      if (nc=='$') // escaped $
+      {
+	g_code->codify("$");
+      }
+      else // name fragment or reference to a nested call 
+      {
+	if (nc=='n') // name fragment
+	{
+          nc=*p++;
+	  QCString refIdStr;
+	  while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
+	  p--;
+	  int refId=refIdStr.toInt();
+	  QCString *pName = g_nameDict.find(refId);
+	  if (pName)
+	  {
+	    if (ctx->method && ctx->method->isLinkable())
+	    {
+              writeMultiLineCodeLink(*g_code,
+		                     ctx->method->getReference(),
+	                             ctx->method->getOutputFileBase(),
+	                             ctx->method->anchor(),
+				     pName->data());
+	      if (g_currentMemberDef)
+	      {
+	        addDocCrossReference(g_currentMemberDef,ctx->method);
+	      }
+	    }
+	    else
+	    {
+   	      codifyLines(pName->data());
+	    }
+	  }
+	  else
+	  {
+	    printf("Invalid name: id=%d\n",refId);
+	  }
+	}
+	else if (nc=='o') // reference to potential object name
+	{
+          nc=*p++;
+	  QCString refIdStr;
+	  while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
+	  p--;
+	  int refId=refIdStr.toInt();
+	  QCString *pObject = g_objectDict.find(refId);
+	  if (pObject)
+	  {
+	    if (*pObject=="self")
+	    {
+	      if (g_currentDefinition && 
+		  g_currentDefinition->definitionType()==Definition::TypeClass)
+	      {
+	        ctx->objectType = (ClassDef *)g_currentDefinition;
+	        if (ctx->objectType->categoryOf()) 
+	        {
+	          ctx->objectType = ctx->objectType->categoryOf();
+	        }
+	        if (ctx->objectType)
+	        {
+	          ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
+	        }
+	      }
+ 	      startFontClass("keyword");
+              codifyLines(pObject->data());
+	      endFontClass();
+	    }
+	    else if (*pObject=="super")
+	    {
+	      if (g_currentDefinition &&
+		  g_currentDefinition->definitionType()==Definition::TypeClass)
+	      {
+		ClassDef *cd = (ClassDef *)g_currentDefinition;
+		if (cd->categoryOf()) 
+		{
+		  cd = cd->categoryOf();
+		}
+		BaseClassList *bcd = cd->baseClasses();
+		if (bcd) // get direct base class (there should be only one)
+		{
+		  BaseClassListIterator bli(*bcd);
+		  BaseClassDef *bclass;
+		  for (bli.toFirst();(bclass=bli.current());++bli)
+		  {
+		    if (bclass->classDef->compoundType()!=ClassDef::Protocol)
+		    {
+		      ctx->objectType = bclass->classDef;
+		      if (ctx->objectType)
+		      {
+			ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
+		      }
+		    }
+		  }
+		}
+	      }
+ 	      startFontClass("keyword");
+              codifyLines(pObject->data());
+	      endFontClass();
+	    }
+	    else if (ctx->objectVar && ctx->objectVar->isLinkable()) // object is class variable
+	    {
+	      writeMultiLineCodeLink(*g_code,
+		    ctx->objectVar->getReference(),
+		    ctx->objectVar->getOutputFileBase(),
+		    ctx->objectVar->anchor(),
+		    pObject->data());
+	      if (g_currentMemberDef)
+	      {
+	        addDocCrossReference(g_currentMemberDef,ctx->objectVar);
+	      }
+	    }
+	    else if (ctx->objectType && 
+		     ctx->objectType!=VariableContext::dummyContext && 
+		     ctx->objectType->isLinkable()
+		    ) // object is class name
+	    {
+	      ClassDef *cd = ctx->objectType;
+	      writeMultiLineCodeLink(*g_code,
+		    cd->getReference(),
+		    cd->getOutputFileBase(),
+		    0,
+		    pObject->data());
+	    }
+	    else // object still needs to be resolved
+	    {
+	      ClassDef *cd = getResolvedClass(g_currentDefinition, 
+		  g_sourceFileDef, *pObject);
+	      if (cd && cd->isLinkable())
+	      {
+		if (ctx->objectType==0) ctx->objectType=cd;
+	   	writeMultiLineCodeLink(*g_code,
+		    cd->getReference(),
+		    cd->getOutputFileBase(),
+		    0,
+		    pObject->data());
+	      }
+	      else
+	      {
+		codifyLines(pObject->data());
+	      }
+	    }
+	  }
+	  else
+	  {
+	    printf("Invalid object: id=%d\n",refId);
+	  }
+	}
+	else if (nc=='c') // reference to nested call
+	{
+          nc=*p++;
+	  QCString refIdStr;
+	  while (nc!=0 && isdigit(nc)) { refIdStr+=nc; nc=*p++; }
+	  p--;
+	  int refId=refIdStr.toInt();
+	  ObjCCallCtx *ictx = g_contextDict.find(refId);
+	  if (ictx) // recurse into nested call
+	  {
+	    writeObjCMethodCall(ictx);
+	    if (ictx->method) // link to nested call successfully
+	    {
+	      // get the ClassDef representing the method's return type
+	      if (QCString(ictx->method->typeString())=="id")
+	      {
+		// see if the method name is unique, if so we link to it
+		MemberName *mn=Doxygen::memberNameSDict.find(ctx->methodName);
+		//printf("mn->count=%d ictx->method=%s ctx->methodName=%s\n",
+		//    mn==0?-1:(int)mn->count(),
+		//    ictx->method->name().data(),
+		//    ctx->methodName.data());
+		if (mn && mn->count()==1) // member name unique
+		{
+		  ctx->method = mn->getFirst();
+		}
+	      } 
+	      else
+	      {
+		ctx->objectType = stripClassName(ictx->method->typeString());
+		if (ctx->objectType)
+		{
+		  ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
+		}
+	      }
+	      //printf("  ***** method=%s -> object=%p\n",ictx->method->name().data(),ctx->objectType);
+	    }
+	  }
+	  else
+	  {
+	    printf("Invalid context: id=%d\n",refId);
+	  }
+	}
+	else // illegal marker
+	{
+	  ASSERT(!"invalid escape sequence");
+	}
+      }
+    }
+    else // normal non-marker character
+    {
+      char s[2];
+      s[0]=c;s[1]=0;
+      codifyLines(s);
+    }
+  }  
+  //printf("%s %s]\n",ctx->objectTypeOrName.data(),ctx->methodName.data());
+  //printf("}=(type='%s',name='%s')",
+  //    ctx->objectTypeOrName.data(),
+  //    ctx->methodName.data());
+}
 
+// Replaces an Objective-C method name fragment s by a marker of the form
+// $n12, the number (12) can later be used as a key for obtaining the name 
+// fragment, from g_nameDict
+static QCString escapeName(const char *s)
+{
+  QCString result;
+  result.sprintf("$n%d",g_currentNameId);
+  g_nameDict.insert(g_currentNameId,new QCString(s));
+  g_currentNameId++;
+  return result;
+}
 
+static QCString escapeObject(const char *s)
+{
+  QCString result;
+  result.sprintf("$o%d",g_currentObjId);
+  g_objectDict.insert(g_currentObjId,new QCString(s));
+  g_currentObjId++;
+  return result;
+}
 
 /* -----------------------------------------------------------------
  */
@@ -1087,6 +1436,7 @@ KEYWORD_OBJC ("@public"|"@private"|"@protected"|"@class"|"@implementation"|"@int
 KEYWORD ("asm"|"auto"|"class"|"const"|"const_cast"|"delete"|"dynamic_cast"|"enum"|"explicit"|"extern"|"false"|"friend"|"inline"|"mutable"|"namespace"|"new"|"operator"|"private"|"protected"|"public"|"register"|"reinterpret_cast"|"sizeof"|"static"|"static_cast"|"struct"|"template"|"this"|"self"|"true"|"typedef"|"typeid"|"typename"|"union"|"using"|"virtual"|"volatile"|"abstract"|"final"|"import"|"synchronized"|"transient"|KEYWORD_OBJC)
 FLOWKW  ("break"|"case"|"catch"|"continue"|"default"|"do"|"else"|"for"|"goto"|"if"|"return"|"switch"|"throw"|"throws"|"try"|"while")
 TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"|"void"|"wchar_t"|"boolean"|"id"|"SEL")
+CHARLIT   (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^' \\\n]{1,4}"'"))
 
 %option noyywrap
 
@@ -1113,9 +1463,9 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
 %x      ObjCMethod
 %x	ObjCParams
 %x	ObjCParamType
-%x	ObjCMemberCall
-%x	ObjCMemberCall2
-%x	ObjCMemberCall3
+%x      ObjCCall
+%x      ObjCMName
+%x      ObjCSkipStr
 
 %%
 
@@ -1146,8 +1496,13 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
 					  endFontClass();
 					  BEGIN( PackageName ); 
 					}
-<Body,ClassVar>"-"|"+"			{
-					  if (!g_insideObjC)
+<ClassVar>\n				{
+  					  if (!g_insideObjC) REJECT;
+  					  codifyLines(yytext);
+					  BEGIN(Body);
+  					}
+<Body,ClassVar,Bases>"-"|"+"		{
+					  if (!g_insideObjC || g_insideBody)
 					  { 
   					    g_code->codify(yytext);
 					  }
@@ -1170,8 +1525,22 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
   					  g_code->codify(yytext);
 					  if (*yytext=='{')
 					  {
-					    g_insideBody=TRUE;
+					    g_curlyCount++;
+					    g_inClass=TRUE;
+  					    if (g_searchingForBody)
+					    {
+					      g_searchingForBody=FALSE;
+					      g_insideBody=TRUE;
+					    }
+					    if (g_insideBody) g_bodyCurlyCount++;
+					    if (!g_curClassName.isEmpty()) // valid class name
+					    {
+					      pushScope(g_curClassName);
+  					      g_scopeStack.push(SCOPEBLOCK);
+					    }
 					  }
+                                          g_type.resize(0);
+                                          g_name.resize(0);
 					  BEGIN(Body);
   					}
 <ObjCParams>{ID}{B}*":"			{
@@ -1313,7 +1682,7 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
 					  }
 					  BEGIN(Body);
 					}
-<Body>"@end"				{ 
+<Body,ClassVar>"@end"			{ 
   					  //printf("End of objc scope fd=%s\n",g_sourceFileDef->name().data());
                                           if (g_sourceFileDef)
 					  {
@@ -1326,12 +1695,16 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
 					  {
 					    g_insideObjC = FALSE;
 					  }
-                                          g_theVarContext.popScope();
-
-					  int *scope = g_scopeStack.pop();
-  					  if (scope==SCOPEBLOCK || scope==CLASSBLOCK) 
+					  if (g_insideBody)
 					  {
-					    popScope();
+                                            g_theVarContext.popScope();
+
+					    int *scope = g_scopeStack.pop();
+  					    if (scope==SCOPEBLOCK || scope==CLASSBLOCK) 
+					    {
+					      popScope();
+					    }
+					    g_insideBody=FALSE;
 					  }
 
 					  startFontClass("keyword");
@@ -1340,7 +1713,6 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
 
   					  g_inClass=FALSE; 
 
-					  g_insideBody=FALSE;
 					  g_currentMemberDef=0;
 					  if (g_currentDefinition) 
 					    g_currentDefinition=g_currentDefinition->getOuterScope();
@@ -1449,9 +1821,20 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
 					}
 <Bases>"<"                              { 
   					  g_code->codify(yytext);
-  					  g_sharpCount=1;
-					  BEGIN ( SkipSharp );
+					  if (!g_insideObjC)
+					  {
+  					    g_sharpCount=1;
+					    BEGIN ( SkipSharp );
+					  }
+					  else
+					  {
+					    g_insideProtocolList=TRUE;
+					  }
 					}
+<Bases>">"				{
+  					  g_code->codify(yytext);
+					  g_insideProtocolList=FALSE;
+  					}
 <SkipSharp>"<"                          {
   					  g_code->codify(yytext);
   					  ++g_sharpCount; 
@@ -1603,7 +1986,7 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
   					  g_name+=yytext; 
   					  BEGIN( FuncCall );
 					}
-<FuncCall,Body,MemberCall,MemberCall2,ObjCMemberCall2,ObjCMemberCall3>\"	{
+<FuncCall,Body,MemberCall,MemberCall2>\"	{
 					  startFontClass("stringliteral");
   					  g_code->codify(yytext);
   					  g_lastStringContext=YY_START;
@@ -1729,9 +2112,19 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
 					  {
 					    //printf("Found start of ObjC call!\n");
 					    // start of a method call
-					    g_code->codify(yytext);
-					    g_theCallContext.pushScope();
-					    BEGIN(ObjCMemberCall);
+					    g_contextDict.setAutoDelete(TRUE);
+					    g_nameDict.setAutoDelete(TRUE);
+					    g_objectDict.setAutoDelete(TRUE);
+					    g_contextDict.clear();
+					    g_nameDict.clear();
+					    g_objectDict.clear();
+					    g_currentCtxId  = 0;
+					    g_currentNameId  = 0;
+					    g_currentObjId  = 0;
+					    g_currentCtx = 0;
+					    g_braceCount = 0;
+					    unput('[');
+					    BEGIN(ObjCCall);
 					  }
 					  else
 					  {
@@ -1758,6 +2151,7 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
 					    g_args.resize(0);
 					  }
   					}
+  /*
 <ObjCMemberCall>{ID}			{
   					  if (strcmp(yytext,"self")==0 || strcmp(yytext,"super")==0)
 					  {
@@ -1802,6 +2196,70 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
   					  g_code->codify(yytext);
 					  BEGIN(Body);
   					}
+  */
+<ObjCCall,ObjCMName>"["         { 
+                                   saveObjCContext();
+			           g_currentCtx->format+=*yytext;
+			           BEGIN(ObjCCall);
+		                   //printf("open\n");
+                                 }
+<ObjCCall,ObjCMName>"]"         { 
+			            g_currentCtx->format+=*yytext;
+                                    restoreObjCContext();
+			            BEGIN(ObjCMName);
+		             	    if (g_currentCtx==0)
+				    {
+				      // end of call
+				      writeObjCMethodCall(g_contextDict.find(0));
+				      BEGIN(Body);
+				    }
+			            //printf("close\n");
+                                  }
+<ObjCCall>{ID}	                  {
+                                    g_currentCtx->format+=escapeObject(yytext);
+			            if (g_braceCount==0)
+			            {
+			              g_currentCtx->objectTypeOrName=yytext;
+                                      //printf("new type=%s\n",g_currentCtx->objectTypeOrName.data());
+			              BEGIN(ObjCMName);
+			            }
+  		                  }
+<ObjCMName>{ID}/{BN}*"]"          { 
+                                    if (g_braceCount==0 && 
+					g_currentCtx->methodName.isEmpty())
+                                    {
+			              g_currentCtx->methodName=yytext; 
+                                      g_currentCtx->format+=escapeName(yytext);
+			            }
+				    else
+				    {
+                                      g_currentCtx->format+=yytext;
+				    }
+                                  }
+<ObjCMName>{ID}/{BN}*":"           { 
+                                     if (g_braceCount==0)
+                                     {
+			               g_currentCtx->methodName+=yytext;
+                                       g_currentCtx->methodName+=":";
+			             }
+                                     g_currentCtx->format+=escapeName(yytext);
+                                   }
+<ObjCSkipStr>[^\n\"$\\]*           { g_currentCtx->format+=yytext; }
+<ObjCSkipStr>\\.	           { g_currentCtx->format+=yytext; }
+<ObjCSkipStr>"\""	           { g_currentCtx->format+=yytext; 
+                                      BEGIN(g_lastStringContext); 
+                                   }
+<ObjCCall,ObjCMName>{CHARLIT}      { g_currentCtx->format+=yytext; }
+<ObjCCall,ObjCMName>"@"?"\""       { g_currentCtx->format+=yytext; 
+                                      g_lastStringContext=YY_START;
+                                      BEGIN(ObjCSkipStr); 
+                                   }
+<ObjCCall,ObjCMName,ObjCSkipStr>"$" { g_currentCtx->format+="$$"; }
+<ObjCCall,ObjCMName>"("            { g_currentCtx->format+=*yytext; g_braceCount++; }
+<ObjCCall,ObjCMName>")"            { g_currentCtx->format+=*yytext; g_braceCount--; }
+<ObjCCall,ObjCMName,ObjCSkipStr>.  { g_currentCtx->format+=*yytext; }
+<ObjCCall,ObjCMName,ObjCSkipStr>\n { g_currentCtx->format+=*yytext; }
+
 <Body>"]"				{
 					  g_theCallContext.popScope();
   					  g_code->codify(yytext);
@@ -2314,6 +2772,52 @@ TYPEKW  ("bool"|"char"|"double"|"float"|"int"|"long"|"short"|"signed"|"unsigned"
 /*@ ----------------------------------------------------------------------------
  */
 
+static void saveObjCContext()
+{
+  if (g_currentCtx)
+  {
+    g_currentCtx->format+=QCString().sprintf("$c%d",g_currentCtxId);
+    if (g_braceCount==0 && YY_START==ObjCCall)
+    {
+      g_currentCtx->objectTypeOrName=g_currentCtx->format.mid(1);
+      //printf("new type=%s\n",g_currentCtx->objectTypeOrName.data());
+    }
+    g_contextStack.push(g_currentCtx);
+  }
+  else
+  {
+    //printf("Trying to save NULL context!\n");
+  }
+  ObjCCallCtx *newCtx = new ObjCCallCtx;
+  newCtx->id = g_currentCtxId;
+  newCtx->lexState = YY_START;
+  newCtx->braceCount = g_braceCount;
+  newCtx->objectType = 0;
+  newCtx->objectVar = 0;
+  newCtx->method = 0;
+  //printf("save state=%d\n",YY_START);
+  g_contextDict.insert(g_currentCtxId,newCtx);
+  g_currentCtx = newCtx;
+  g_braceCount = 0;
+  g_currentCtxId++;
+}
+
+static void restoreObjCContext()
+{
+  //printf("restore state=%d->%d\n",YY_START,g_currentCtx->lexState);
+  BEGIN(g_currentCtx->lexState);
+  g_braceCount = g_currentCtx->braceCount;
+  if (!g_contextStack.isEmpty())
+  {
+    g_currentCtx = g_contextStack.pop();
+  }
+  else
+  {
+    g_currentCtx = 0;
+    //printf("Trying to pop context while g_contextStack is empty!\n");
+  }
+}
+
 void initParseCodeContext()
 {
   g_theVarContext.clear();
diff --git a/src/compound.xsd b/src/compound.xsd
index aa45adf..ac77e4b 100644
--- a/src/compound.xsd
+++ b/src/compound.xsd
@@ -121,6 +121,8 @@
     <xsd:attribute name="virt" type="DoxVirtualKind" />
     <xsd:attribute name="volatile" type="DoxBool" />
     <xsd:attribute name="mutable" type="DoxBool" />
+    <xsd:attribute name="readable" type="DoxBool" use="optional"/>
+    <xsd:attribute name="writable" type="DoxBool" use="optional"/>
   </xsd:complexType>
 
   <xsd:complexType name="descriptionType" mixed="true">
diff --git a/src/compound_xsd.h b/src/compound_xsd.h
index d43646e..6af2a92 100644
--- a/src/compound_xsd.h
+++ b/src/compound_xsd.h
@@ -121,6 +121,8 @@
 "    <xsd:attribute name=\"virt\" type=\"DoxVirtualKind\" />\n"
 "    <xsd:attribute name=\"volatile\" type=\"DoxBool\" />\n"
 "    <xsd:attribute name=\"mutable\" type=\"DoxBool\" />\n"
+"    <xsd:attribute name=\"readable\" type=\"DoxBool\" use=\"optional\"/>\n"
+"    <xsd:attribute name=\"writable\" type=\"DoxBool\" use=\"optional\"/>\n"
 "  </xsd:complexType>\n"
 "\n"
 "  <xsd:complexType name=\"descriptionType\" mixed=\"true\">\n"
diff --git a/src/config.l b/src/config.l
index e63d0bb..f757a3d 100644
--- a/src/config.l
+++ b/src/config.l
@@ -829,6 +829,41 @@ void Config::substituteEnvironmentVars()
   }
 }
 
+static void cleanUpPaths(QStrList &str)
+{
+  char *sfp = str.first();
+  while (sfp)
+  {
+    register char *p = sfp;
+    if (p)
+    {
+      char c;
+      while ((c=*p))
+      {
+	if (c=='\\') *p='/';
+	p++;
+      }
+    }
+    QCString path = sfp;
+    if ((path.at(0)!='/' && (path.length()<=2 || path.at(1)!=':')) ||
+	path.at(path.length()-1)!='/'
+       )
+    {
+      QFileInfo fi(path);
+      if (fi.exists() && fi.isDir())
+      {
+	int i = str.at();
+	str.remove();
+	if (str.at()==i) // did not remove last item
+	  str.insert(i,fi.absFilePath()+"/");
+	else
+	  str.append(fi.absFilePath()+"/");
+      }
+    }
+    sfp = str.next();
+  }
+}
+
 void Config::check()
 {
   //if (!projectName.isEmpty())
@@ -903,36 +938,12 @@ void Config::check()
   }
   else
   {
-    while (sfp)
-    {
-      register char *p = sfp;
-      if (p)
-      {
-	char c;
-	while ((c=*p))
-	{
-	  if (c=='\\') *p='/';
-	  p++;
-	}
-      }
-      QCString path = sfp;
-      if (path.at(0)!='/' && (path.length()<=2 || path.at(1)!=':'))
-      {
-	QFileInfo fi(path);
-	if (fi.exists() && fi.isDir())
-	{
-	  int i = stripFromPath.at();
-	  stripFromPath.remove();
-	  if (stripFromPath.at()==i) // did not remove last item
-	    stripFromPath.insert(i,fi.absFilePath()+"/");
-	  else
-	    stripFromPath.append(fi.absFilePath()+"/");
-	}
-      }
-      sfp = stripFromPath.next();
-    }
+    cleanUpPaths(stripFromPath);
   }
-  
+
+  // expand the relative stripFromPath values
+  QStrList &stripFromIncPath = Config_getList("STRIP_FROM_INC_PATH");
+  cleanUpPaths(stripFromIncPath);
   
   // Test to see if HTML header is valid
   QCString &headerFile = Config_getString("HTML_HEADER");
@@ -1102,6 +1113,22 @@ void Config::check()
     filePatternList.append("*.inc");
     filePatternList.append("*.m");
     filePatternList.append("*.mm");
+#if !defined(_WIN32)
+    // unix => case sensitive match => also include useful uppercase versions
+    filePatternList.append("*.C");
+    filePatternList.append("*.CC"); 
+    filePatternList.append("*.C++");
+    filePatternList.append("*.II");
+    filePatternList.append("*.I++");
+    filePatternList.append("*.H");
+    filePatternList.append("*.HH");
+    filePatternList.append("*.H++");
+    filePatternList.append("*.CS");
+    filePatternList.append("*.PHP");
+    filePatternList.append("*.PHP3");
+    filePatternList.append("*.M");
+    filePatternList.append("*.MM");
+#endif
   }
 
   // add default pattern if needed
@@ -1495,11 +1522,20 @@ void Config::create()
                     "If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \n"
                     "can be used to strip a user-defined part of the path. Stripping is \n"
                     "only done if one of the specified strings matches the left-hand part of \n"
-                    "the path. It is allowed to use relative paths in the argument list. \n"
+                    "the path. The tag can be used to show relative paths in the file list. \n"
 		    "If left blank the directory from which doxygen is run is used as the \n"
 		    "path to strip. \n"
                  );
   cl->addDependency("FULL_PATH_NAMES");
+  cl = addList(
+                    "STRIP_FROM_INC_PATH",
+                    "The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of \n"
+		    "the path mentioned in the documentation of a class, which tells \n"
+		    "the reader which header file to include in order to use a class. \n"
+		    "If left blank only the name of the header file containing the class \n"
+		    "definition is used. Otherwise one should specify the include paths that \n"
+		    "are normally passed to the compiler using the -I flag.\n"
+                 );
   cb = addBool(
                     "SHORT_NAMES",
 		    "If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \n"
@@ -2454,7 +2490,7 @@ void Config::create()
                     "INCLUDE_PATH",
                     "The INCLUDE_PATH tag can be used to specify one or more directories that \n"
                     "contain include files that are not input files but should be processed by \n"
-                    "the preprocessor. \n"
+                    "the preprocessor.\n"
                  );
   cl->setWidgetType(ConfigList::Dir);
   cl->addDependency("ENABLE_PREPROCESSING");
diff --git a/src/docparser.cpp b/src/docparser.cpp
index ee0d83a..33cccff 100644
--- a/src/docparser.cpp
+++ b/src/docparser.cpp
@@ -1247,6 +1247,8 @@ void DocInclude::parse()
   DBG(("DocInclude::parse(file=%s,text=%s)\n",m_file.data(),m_text.data()));
   switch(m_type)
   {
+    case IncWithLines:
+      // fall through
     case Include:
       // fall through
     case DontInclude:
@@ -3819,6 +3821,9 @@ int DocPara::handleCommand(const QString &cmdName)
     case CMD_INCLUDE:
       handleInclude(cmdName,DocInclude::Include);
       break;
+    case CMD_INCWITHLINES:
+      handleInclude(cmdName,DocInclude::IncWithLines);
+      break;
     case CMD_DONTINCLUDE:
       handleInclude(cmdName,DocInclude::DontInclude);
       break;
diff --git a/src/docparser.h b/src/docparser.h
index 6ccb05c..8df9c53 100644
--- a/src/docparser.h
+++ b/src/docparser.h
@@ -380,7 +380,7 @@ class DocVerbatim : public DocNode
 class DocInclude : public DocNode
 {
   public:
-    enum Type { Include, DontInclude, VerbInclude, HtmlInclude };
+    enum Type { Include, DontInclude, VerbInclude, HtmlInclude, IncWithLines };
     DocInclude(DocNode *parent,const QString &file,
                const QString context, Type t,
                bool isExample,const QString exampleFile) : 
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 8a1dcec..d71e7c1 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -488,6 +488,10 @@ static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
           iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
         }
       }
+      else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty()) 
+      {
+        iName=stripFromIncludePath(fd->absFilePath());
+      }
       else // use name of the file containing the class definition
       {
         iName=fd->name();
@@ -822,21 +826,6 @@ static void addClassToContext(Entry *root)
     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
     cd->insertUsedFile(root->fileName);
 
-    //int bi;
-    //if (root->objc && (bi=fullName.find('<'))!=-1 && root->extends->count()==0)
-    //{
-    //  // add protocols as base classes
-    //  int be=fullName.find('>'),len;
-    //  static QRegExp re("[A-Z_a-z][A-Z_a-z0-9]*");
-    //  int p=0;
-    //  while ((p=re.match(fullName,bi+1,&len))!=-1 && p<be)
-    //  {
-    //    QCString baseName = fullName.mid(p,len);
-    //    printf("Adding artifical base class %s to %s\n",baseName.data(),fullName.data());
-    //    root->extends->append(new BaseInfo(baseName,Public,Normal));
-    //    bi=p+len; 
-    //  }
-    //}
 
     // add class to the list
     //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());
@@ -5754,10 +5743,26 @@ static void createTemplateInstanceMembers()
 static void buildCompleteMemberLists()
 {
   ClassDef *cd;
-  // merge the member list of base classes into the inherited classes.
+  // merge members of categories into the class they extend
   ClassSDict::Iterator cli(Doxygen::classSDict);
   for (cli.toFirst();(cd=cli.current());++cli)
   {
+    int i=cd->name().find('(');
+    if (i!=-1) // it is an Objective-C category
+    {
+      QCString baseName=cd->name().left(i);
+      ClassDef *baseClass=Doxygen::classSDict.find(baseName);
+      if (baseClass)
+      {
+        //printf("*** merging members of category %s into %s\n",
+        //    cd->name().data(),baseClass->name().data());
+        baseClass->mergeCategory(cd);
+      }
+    }
+  }
+  // merge the member list of base classes into the inherited classes.
+  for (cli.toFirst();(cd=cli.current());++cli)
+  {
     if (// !cd->isReference() && // not an external class
          cd->subClasses()->count()==0 && // is a root of the hierarchy
          cd->baseClasses()->count()>0) // and has at least one base class
@@ -8372,6 +8377,7 @@ void generateOutput()
       exit(1);
     }
     Doxygen::tagFile.setDevice(tag);
+    Doxygen::tagFile.setEncoding(QTextStream::Latin1);
     Doxygen::tagFile << "<?xml version='1.0' encoding='ISO-8859-1' standalone='yes'?>" << endl;
     Doxygen::tagFile << "<tagfile>" << endl;
   }
diff --git a/src/entry.h b/src/entry.h
index 4670a48..63ead7e 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -38,7 +38,8 @@ struct ListItemInfo
 struct BaseInfo 
 {
   /*! Creates an object representing an inheritance relation */
-  BaseInfo(const char *n,Protection p,Specifier v) : name(n),prot(p),virt(v) {}
+  BaseInfo(const char *n,Protection p,Specifier v) : 
+    name(n),prot(p),virt(v) {}
   QCString   name; //!< the name of the base class
   Protection prot; //!< inheritance type
   Specifier  virt; //!< virtualness
diff --git a/src/filedef.cpp b/src/filedef.cpp
index 0642245..b04c5e3 100644
--- a/src/filedef.cpp
+++ b/src/filedef.cpp
@@ -55,7 +55,7 @@ class DevNullCodeDocInterface : public BaseCodeDocInterface
 
 
 /*! create a new file definition, where \a p is the file path, 
-    \a the file name, and \a ref is an HTML anchor name if the
+    \a nm the file name, and \a ref is an HTML anchor name if the
     file was read from a tag file or 0 otherwise
 */
 FileDef::FileDef(const char *p,const char *nm,
diff --git a/src/htmldocvisitor.cpp b/src/htmldocvisitor.cpp
index 6d46942..a2ca11f 100644
--- a/src/htmldocvisitor.cpp
+++ b/src/htmldocvisitor.cpp
@@ -171,6 +171,7 @@ void HtmlDocVisitor::visit(DocStyleChange *s)
         m_insidePre=FALSE;
         m_t << "</pre>";
       }
+      break;
     case DocStyleChange::Div:
       if (s->enable()) m_t << "<div" << htmlAttribsToString(s->attribs()) << ">";  else m_t << "</div>";
       break;
@@ -245,9 +246,18 @@ void HtmlDocVisitor::visit(DocInclude *inc)
   switch(inc->type())
   {
     case DocInclude::Include: 
-      m_t << "<div class=\"fragment\"><pre>";
+      m_t << "<pre class=\"fragment\"><div>";
       parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile());
-      m_t << "</pre></div>"; 
+      m_t << "</div></pre>"; 
+    case DocInclude::IncWithLines:
+      { 
+         m_t << "<div class=\"fragment\"><pre>";
+         QFileInfo cfi( inc->file() );
+         FileDef fd( cfi.dirPath(), cfi.fileName() );
+         parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
+         m_t << "</pre></div>"; 
+      }
+      break;
       break;
     case DocInclude::DontInclude: 
       break;
@@ -255,9 +265,9 @@ void HtmlDocVisitor::visit(DocInclude *inc)
       m_t << inc->text(); 
       break;
     case DocInclude::VerbInclude: 
-      m_t << "<div class=\"fragment\"><pre>";
+      m_t << "<pre class=\"fragment\"><div>";
       filter(inc->text());
-      m_t << "</pre></div>"; 
+      m_t << "</div></pre>"; 
       break;
   }
 }
@@ -268,7 +278,7 @@ void HtmlDocVisitor::visit(DocIncOperator *op)
   //    op->type(),op->isFirst(),op->isLast(),op->text().data());
   if (op->isFirst()) 
   {
-    if (!m_hide) m_t << "<div class=\"fragment\"><pre>";
+    if (!m_hide) m_t << "<pre class=\"fragment\"><div>";
     pushEnabled();
     m_hide=TRUE;
   }
@@ -282,7 +292,7 @@ void HtmlDocVisitor::visit(DocIncOperator *op)
   if (op->isLast())  
   {
     popEnabled();
-    if (!m_hide) m_t << "</pre></div>"; 
+    if (!m_hide) m_t << "</div></pre>"; 
   }
   else
   {
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp
index 46a797e..1e5666a 100644
--- a/src/htmlgen.cpp
+++ b/src/htmlgen.cpp
@@ -34,11 +34,12 @@
 #include "htmldocvisitor.h"
 #include "index.h"
 #include "pagedef.h"
+#include "debug.h"
 
 // #define GROUP_COLOR "#ff8080"
 
-#define DBG_HTML(x) x;
-//#define DBG_HTML(x) 
+//#define DBG_HTML(x) x;
+#define DBG_HTML(x) 
 
 static const char *defaultStyleSheet = 
 "H1 {\n"
@@ -308,7 +309,7 @@ void HtmlGenerator::writeStyleSheetFile(QFile &file)
 }
 
 static void writeDefaultHeaderFile(QTextStream &t, const char *title,
-                                   const char *relPath)
+                                   const char *relPath,bool usePathCmd)
 {
   t << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
     "<html><head>" 
@@ -321,7 +322,11 @@ static void writeDefaultHeaderFile(QTextStream &t, const char *title,
   t << "href=\"";
   if (Config_getString("HTML_STYLESHEET").isEmpty())
   {
-    t << relPath << "doxygen.css";
+    if (usePathCmd) 
+      t << "$relpath$";
+    else
+      t << relPath;
+    t << "doxygen.css";
   }
   else
   {
@@ -344,7 +349,7 @@ void HtmlGenerator::writeHeaderFile(QFile &file)
 #if QT_VERSION >= 200
   t.setEncoding(QTextStream::Latin1);
 #endif
-  writeDefaultHeaderFile(t,"$title",relativePathToRoot(0));
+  writeDefaultHeaderFile(t,"$title",relativePathToRoot(0),TRUE);
 }
 
 void HtmlGenerator::writeFooterFile(QFile &file)
@@ -390,11 +395,11 @@ void HtmlGenerator::startFile(const char *name,const char *,
   lastFile = fileName;
   if (g_header.isEmpty()) 
   {
-    writeDefaultHeaderFile(t,dispTitle,relPath);
+    writeDefaultHeaderFile(t,dispTitle,relPath,FALSE);
   }
   else
   {
-    t << substituteKeywords(g_header,convertToHtml(lastTitle));
+    t << substituteKeywords(g_header,convertToHtml(lastTitle),relPath);
   }
   t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen " 
     << versionString << " -->" << endl;
@@ -442,11 +447,22 @@ static void writePageFooter(QTextStream &t,const QCString &lastTitle,
     t << endl << "<a href=\"http://www.doxygen.org/index.html\">";
     t << endl << "<img src=\"" << relPath << "doxygen.png\" alt=\"doxygen\" " 
       << "align=\"middle\" border=0 >" << "</a> " << versionString << " ";
-    t << "</small></address>\n</body>\n</html>\n";
+    t << "</small></address>";
+    if (Debug::isFlagSet(Debug::Validate))
+    {
+      t << "<p><a href=\"http://validator.w3.org/check/referer\">"
+           "<img border=\"0\" src=\"http://www.w3.org/Icons/valid-html401\""
+           " height=\"31\" width=\"88\" alt=\"This page is Valid HTML 4.01 "
+           "Transitional!\"></a><a href=\"http://jigsaw.w3.org/css-validator/\">"
+           "<img style=\"border:0;width:88px;height:31px\" "
+           "src=\"http://jigsaw.w3.org/css-validator/images/vcss\" "
+           "alt=\"This page uses valid CSS!\"></a></p>";
+    }
+    t << "\n</body>\n</html>\n";
   }
   else
   {
-    t << substituteKeywords(g_footer,convertToHtml(lastTitle));
+    t << substituteKeywords(g_footer,convertToHtml(lastTitle),relPath);
   }
 }
 
@@ -1482,11 +1498,11 @@ void HtmlGenerator::writeSearchPage()
 #endif
       if (g_header.isEmpty()) 
       {
-        writeDefaultHeaderFile(t,"Search",0);
+        writeDefaultHeaderFile(t,"Search",0,FALSE);
       }
       else
       {
-        t << substituteKeywords(g_header,"Search");
+        t << substituteKeywords(g_header,"Search","");
       }
       t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen " 
         << versionString << " -->" << endl;
diff --git a/src/htmlgen.h b/src/htmlgen.h
index f06318f..29d7385 100644
--- a/src/htmlgen.h
+++ b/src/htmlgen.h
@@ -112,8 +112,8 @@ class HtmlGenerator : public OutputGenerator
     void writeRuler()    { t << "<hr>"; }
     void writeAnchor(const char *,const char *name) 
                          { t << "<a name=\"" << name <<"\"></a>"; }
-    void startCodeFragment() { t << "<div class=\"fragment\"><pre>"; }
-    void endCodeFragment()   { t << "</pre></div>"; } 
+    void startCodeFragment() { t << "<pre class=\"fragment\"><div>"; }
+    void endCodeFragment()   { t << "</div></pre>"; } 
     void writeLineNumber(const char *,const char *,const char *,int);
     void startCodeLine() { col=0; }
     void endCodeLine()   { codify("\n"); }
diff --git a/src/index.cpp b/src/index.cpp
index ecbf8dd..afc0f1d 100644
--- a/src/index.cpp
+++ b/src/index.cpp
@@ -3048,7 +3048,7 @@ void writeIndex(OutputList &ol)
   QCString defFileName = 
     Doxygen::mainPage ? Doxygen::mainPage->getDefFileName().data() : "<generated>";
   int defLine =
-    Doxygen::mainPage ? Doxygen::mainPage->getDefLine() : 1;
+    Doxygen::mainPage ? Doxygen::mainPage->getDefLine() : -1;
 
   QCString title;
   if (!mainPageHasTitle())
diff --git a/src/latexdocvisitor.cpp b/src/latexdocvisitor.cpp
index 0cb1bae..0da3849 100644
--- a/src/latexdocvisitor.cpp
+++ b/src/latexdocvisitor.cpp
@@ -15,7 +15,7 @@
  * input used in their production; they are not affected by this license.
  *
  */
-
+#include <qfileinfo.h> 
 #include "latexdocvisitor.h"
 #include "docparser.h"
 #include "language.h"
@@ -308,6 +308,15 @@ void LatexDocVisitor::visit(DocInclude *inc)
   if (m_hide) return;
   switch(inc->type())
   {
+    case DocInclude::IncWithLines:
+      { 
+         m_t << "\n\n\\footnotesize\\begin{verbatim}"; 
+         QFileInfo cfi( inc->file() );
+         FileDef fd( cfi.dirPath(), cfi.fileName() );
+         parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
+         m_t << "\\end{verbatim}\n\\normalsize" << endl; 
+      }
+      break;    
     case DocInclude::Include: 
       m_t << "\n\n\\footnotesize\\begin{verbatim}"; 
       parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile());
diff --git a/src/mandocvisitor.cpp b/src/mandocvisitor.cpp
index 2345670..b560a27 100644
--- a/src/mandocvisitor.cpp
+++ b/src/mandocvisitor.cpp
@@ -25,6 +25,7 @@
 #include "dot.h"
 #include "util.h"
 #include "message.h"
+#include <qfileinfo.h> 
 
 ManDocVisitor::ManDocVisitor(QTextStream &t,BaseCodeDocInterface &ci) 
   : DocVisitor(DocVisitor_Man), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE), m_firstCol(TRUE),
@@ -220,6 +221,19 @@ void ManDocVisitor::visit(DocInclude *inc)
   if (m_hide) return;
   switch(inc->type())
   {
+    case DocInclude::IncWithLines:
+      { 
+         if (!m_firstCol) m_t << endl;
+         m_t << ".PP" << endl;
+         m_t << ".nf" << endl;
+         QFileInfo cfi( inc->file() );
+         FileDef fd( cfi.dirPath(), cfi.fileName() );
+         parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
+         if (!m_firstCol) m_t << endl;
+         m_t << ".PP" << endl;
+         m_firstCol=TRUE;
+      }
+      break;
     case DocInclude::Include: 
       if (!m_firstCol) m_t << endl;
       m_t << ".PP" << endl;
diff --git a/src/memberlist.cpp b/src/memberlist.cpp
index a995904..8a3ace5 100644
--- a/src/memberlist.cpp
+++ b/src/memberlist.cpp
@@ -323,7 +323,7 @@ void MemberList::writeDeclarations(OutputList &ol,
   {
     //printf("subtitle=`%s'\n",subtitle);
     ol.startMemberSubtitle();
-    ol.parseDoc("<generated>",1,0,0,subtitle,FALSE,FALSE);
+    ol.parseDoc("<generated>",-1,0,0,subtitle,FALSE,FALSE);
     ol.endMemberSubtitle();
   }
 
@@ -347,7 +347,7 @@ void MemberList::writeDeclarations(OutputList &ol,
       {
         //printf("Member group has docs!\n");
         ol.startMemberGroupDocs();
-        ol.parseDoc("<generated>",1,0,0,mg->documentation()+"\n",FALSE,FALSE);
+        ol.parseDoc("<generated>",-1,0,0,mg->documentation()+"\n",FALSE,FALSE);
         ol.endMemberGroupDocs();
       }
       ol.startMemberGroup();
diff --git a/src/perlmodgen.cpp b/src/perlmodgen.cpp
index 20520c1..c5c9858 100644
--- a/src/perlmodgen.cpp
+++ b/src/perlmodgen.cpp
@@ -642,6 +642,18 @@ void PerlModDocVisitor::visit(DocInclude *inc)
   const char *type = 0;
   switch(inc->type())
   {
+  case DocInclude::IncWithLines:
+  #if 0
+      { 
+         m_t << "<div class=\"fragment\"><pre>";
+         QFileInfo cfi( inc->file() );
+         FileDef fd( cfi.dirPath(), cfi.fileName() );
+         parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
+         m_t << "</pre></div>"; 
+      }
+      break;
+  #endif
+    return;
   case DocInclude::Include:
 #if 0
     m_output.add("<programlisting>");
diff --git a/src/pre.l b/src/pre.l
index 490f2f5..c57f35b 100644
--- a/src/pre.l
+++ b/src/pre.l
@@ -1862,12 +1862,12 @@ CHARLIT   (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
   					}
 <DefineText>\\[\r]?\n			{ 
 					  g_defLitText+=yytext;
-  					  outputChar('\n');
+					  outputChar('\n');
   					  g_defText += ' '; g_yyLineNr++; 
 					}
 <DefineText>\n				{
-					  g_defLitText+=yytext;
 					  QCString comment=extractTrailingComment(g_defLitText);
+					  g_defLitText+=yytext;
 					  if (!comment.isEmpty())
 					  {
 					    outputArray(comment,comment.length());
diff --git a/src/printdocvisitor.h b/src/printdocvisitor.h
index 52062ec..a7a8b44 100644
--- a/src/printdocvisitor.h
+++ b/src/printdocvisitor.h
@@ -170,6 +170,7 @@ class PrintDocVisitor : public DocVisitor
       switch(inc->type())
       {
         case DocInclude::Include: printf("include"); break;
+        case DocInclude::IncWithLines: printf("incwithlines"); break;
         case DocInclude::DontInclude: printf("dontinclude"); break;
         case DocInclude::HtmlInclude: printf("htmlinclude"); break;
         case DocInclude::VerbInclude: printf("verbinclude"); break;
diff --git a/src/rtfdocvisitor.cpp b/src/rtfdocvisitor.cpp
index 6c65ee2..2f2dd25 100644
--- a/src/rtfdocvisitor.cpp
+++ b/src/rtfdocvisitor.cpp
@@ -26,6 +26,7 @@
 #include "util.h"
 #include "rtfstyle.h"
 #include "message.h"
+#include <qfileinfo.h> 
 
 RTFDocVisitor::RTFDocVisitor(QTextStream &t,BaseCodeDocInterface &ci) 
   : DocVisitor(DocVisitor_RTF), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE), m_indentLevel(1) 
@@ -366,7 +367,19 @@ void RTFDocVisitor::visit(DocInclude *inc)
   if (m_hide) return;
   switch(inc->type())
   {
-    case DocInclude::Include: 
+   case DocInclude::IncWithLines:
+      { 
+         m_t << "{" << endl;
+         m_t << "\\par" << endl;
+         m_t << rtf_Style_Reset << getStyle("CodeExample");
+         QFileInfo cfi( inc->file() );
+         FileDef fd( cfi.dirPath(), cfi.fileName() );
+         parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
+         m_t << "\\par" << endl; 
+         m_t << "}" << endl;
+      }
+      break;
+   case DocInclude::Include: 
       m_t << "{" << endl;
       m_t << "\\par" << endl;
       m_t << rtf_Style_Reset << getStyle("CodeExample");
diff --git a/src/scanner.l b/src/scanner.l
index 349f156..457f5b0 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -79,7 +79,8 @@ static int              lastSkipHtmlCommentContext;
 static int              lastIfContext;
 static int              lastInternalDocContext;
 static int              lastPreLineCtrlContext;
-static int              lastSkipVerbStringContext;;
+static int              lastSkipVerbStringContext;
+static int              lastCommentInArgContext;
 static int              nextDefContext;
 static int              overloadContext;
 static Protection	protection;
@@ -130,6 +131,7 @@ static bool             insideD = FALSE;		//!< processing D code?
 static bool             insidePHP = FALSE;		//!< processing PHP code?
 static bool             insideCppQuote = FALSE;
 static bool             insideObjC = FALSE;             //!< processing Objective C code?
+static bool             insideProtocolList = FALSE;
 
 static int              argRoundCount;
 static int              argSharpCount;
@@ -806,6 +808,7 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 %x      ObjCReturnType
 %x      ObjCParams
 %x      ObjCParamType
+%x      ObjCProtocolList
 %x	QtPropType
 %x	QtPropName
 %x	QtPropRW
@@ -2745,6 +2748,7 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 					    // as documentation for the argument
 					    fullArgString+=yytext;
 					    lastCopyArgChar=0;
+					    lastCommentInArgContext=YY_START;
 					    if (yytext[1]=='/')
 					      BEGIN( CopyArgCommentLine );
 					    else
@@ -2794,6 +2798,7 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 					    lastCopyArgChar=*yytext;
 					    QCString text=&yytext[1];
 					    text=text.stripWhiteSpace();
+					    lastCommentInArgContext=YY_START;
 					    fullArgString+=text;
 					    if (text.find("//")!=-1)
 					      BEGIN( CopyArgCommentLine );
@@ -2806,13 +2811,13 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 <CopyArgComment>"*/"			{ fullArgString+=yytext; 
   					  if (lastCopyArgChar!=0)
 					    unput(lastCopyArgChar); 
-                                          BEGIN( ReadFuncArgType ); 
+                                          BEGIN( lastCommentInArgContext ); 
 					}
 <CopyArgCommentLine>\n			{ fullArgString+=yytext;
   					  yyLineNr++;
   					  if (lastCopyArgChar!=0)
 					    unput(lastCopyArgChar);
-					  BEGIN( ReadFuncArgType );
+					  BEGIN( lastCommentInArgContext );
   					}
 <CopyArgCommentLine>[^\\\@\n]+		{ fullArgString+=yytext; }
 <CopyArgCommentLine>.			{ fullArgString+=*yytext; }
@@ -3347,10 +3352,25 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 <CompoundName>{SCOPENAME}{BN}*/"<"	{
   					  sharpCount = 0;
   					  current->name = yytext ;
+					  if (current->section==Entry::PROTOCOL_SEC)
+					  {
+					    current->name+="-p";
+					  }
 					  lineCount();
 					  lastClassTemplSpecContext = ClassVar;
-					  BEGIN( ClassTemplSpec );
+					  if (insideObjC) // protocol list
+					  {
+					    BEGIN( ObjCProtocolList );
+					  }
+					  else // C++ template specialization
+					  {
+					    BEGIN( ClassTemplSpec );
+					  }
 					}
+<ObjCProtocolList>"<"			{
+  					  insideProtocolList=TRUE;
+  					  BEGIN( Bases );
+  					}
 <ClassTemplSpec>">"({BN}*"::"{BN}*{SCOPENAME})?	{
 					  current->name += yytext;
 					  lineCount();
@@ -3386,8 +3406,12 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 <CompoundName>{SCOPENAME}		{ 
 					  current->name = yytext ;
 					  lineCount();
-					  if (current->section == Entry::PROTOCOL_SEC || 
-					      current->section == Entry::OBJCIMPL_SEC)
+					  if (current->section == Entry::PROTOCOL_SEC)
+					  {
+					    current->name += "-p";
+					  }
+					  if (current->section == Entry::PROTOCOL_SEC /*|| 
+					      current->section == Entry::OBJCIMPL_SEC*/)
 					  {
 					    unput('{'); // fake start of body
 					  }
@@ -3440,21 +3464,9 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 					  }
 					  else
 					  {
-					    //if (isTypedef)
-					    //{
-					    //  //QCString dest = extractName(current->name);
-				   	    //  //printf("3>>>>>>>>>> adding %s->%s\n",yytext,current->name.data());
-					    //  QCString scope;
-					    //  if (current_root->section & Entry::SCOPE_MASK) scope=current_root->name;
-                                            //  Doxygen::typedefDict.insert(yytext,new TypedefInfo(current->name,scope));
-					    //  //current->extends->append(
-					    //  //   new BaseInfo(yytext,Public,Normal)
-					    //  //		      );
-					    //}
 					    current->type += ' ' ;
 					    current->type += current->name ;
 					    current->name = yytext ;
-					    //BEGIN( FindMembers );
 					  }
   					}
 <ClassVar>[(\[]				{
@@ -3532,19 +3544,8 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 <BasesProt>{BN}				{ lineCount(); }
 <BasesProt>.				{ unput(*yytext); BEGIN(Bases); }
 <Bases>("::")?{BN}*({ID}{BN}*"::"{BN}*)*{ID}	{ 
-  					  //QCString bName = yytext;
-					  //bName = bName.stripWhiteSpace();
-  					  //bool globalScope = bName.at(0)==':' && baseName.isEmpty();
-  					  //if (!globalScope)
-  					  //  baseName += bName;
-					  //else
-					  //  baseName += (bName.data()+2);
   					  baseName+=yytext;
 					  current->args += ' ';
-					  //if (!globalScope)
-					  //  current->args += bName;
-					  //else
-					  //  current->args += (bName.data()+2);
 					  current->args += yytext;
 					}
 <Bases>{BN}*{ID}("."{ID})*		{ // Java style class
@@ -3553,16 +3554,17 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 					  current->args += ' ';
 					  current->args += name;
     					}
-<Bases>^{B}*/[\-+]			{
-  					  if (!insideObjC)
-					  { 
+<ClassVar,Bases>\n/{BN}*		{
+                                          if (!insideObjC) 
+					  {
 					    REJECT;
 					  }
 					  else
 					  {
-					    unput('{'); // insert start of fake body
+					    yyLineNr++;
+					    unput('{');
 					  }
-  					}
+					}
 <ClassVar,Bases>"@end"			{ // empty ObjC interface
   					  unput('d'); // insert fake body: {}@end
   					  unput('n'); 
@@ -3577,11 +3579,19 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 					  specName = &current->name;
 					  BEGIN ( Specialization );
 					}
-<Bases>"<"   	       	                { baseName += *yytext;
+<Bases>"<"   	       	                { 
   					  sharpCount=1; 
 					  lastSkipSharpContext = YY_START;
-					  specName = &baseName;
-					  BEGIN ( Specialization );
+					  if (insideObjC) // start of protocol list
+					  {
+					    unput(',');
+					  }
+					  else // template specialization
+					  {
+                                            baseName += *yytext;
+					    specName = &baseName;
+					    BEGIN ( Specialization );
+					  }
 					}
 <Specialization>"<"			{ *specName += *yytext;
   					  sharpCount++;
@@ -3606,22 +3616,46 @@ PHPKW	  ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
 <SkipRound>")"				{ if (--roundCount<=0)
 					    BEGIN ( lastSkipRoundContext );
 					}
-<Bases>","|({BN}+"implements"{BN}*)	{ lineCount();
-                                          current->args += ',' ; 
+<Bases>","|">"|({BN}+"implements"{BN}*)	{ lineCount();
+                                          if (insideProtocolList)
+					  {
+					    baseName+="-p";
+					  }
+					  else
+					  {
+                                            current->args += ',' ; 
+					  }
 					  current->name = removeRedundantWhiteSpace(current->name);
   					  if (!baseName.isEmpty())
+					  {
   					    current->extends->append(
 					      new BaseInfo(baseName,baseProt,baseVirt)
 					    );
+					  }
 					  if (current->section==Entry::INTERFACE_SEC || 
 					      insideJava || insidePHP || insideCS || 
 					      insideD || insideObjC)
+					  {
 					    baseProt=Public;
+					  }
 					  else
+					  {
 					    baseProt=Private;
+					  }
 					  baseVirt=Normal;
 					  baseName.resize(0);
-					  BEGIN(BasesProt);
+                                          if (*yytext=='>')
+					  { // end of a ObjC protocol list
+  					    insideProtocolList=FALSE;
+					  }
+					  else
+					  {
+					    if (*yytext==',' && insideObjC) // Begin of protocol list
+					    {
+  					      insideProtocolList=TRUE;
+					    }
+					    BEGIN(BasesProt);
+					  }
 					}
 <Bases>{B}*"{"{B}*			{ current->fileName = yyFileName ;
 					  current->startLine = yyLineNr ;
diff --git a/src/tagreader.cpp b/src/tagreader.cpp
index f3b5ee8..d8df9f8 100644
--- a/src/tagreader.cpp
+++ b/src/tagreader.cpp
@@ -950,6 +950,7 @@ void TagFileParser::buildMemberList(Entry *ce,QList<TagMemberInfo> &members)
     else if (tmi->kind=="typedef")
     {
       me->section = Entry::VARIABLE_SEC; //Entry::TYPEDEF_SEC;
+      me->type.prepend("typedef ");
       me->mtype = Method;
     }
     else if (tmi->kind=="enumeration")
@@ -975,6 +976,7 @@ void TagFileParser::buildMemberList(Entry *ce,QList<TagMemberInfo> &members)
     else if (tmi->kind=="friend")
     {
       me->section = Entry::FUNCTION_SEC;
+      me->type.prepend("friend ");
       me->mtype = Method;
     }
     else if (tmi->kind=="dcop")
diff --git a/src/translator_hu.h b/src/translator_hu.h
index ee6a438..ab61b18 100644
--- a/src/translator_hu.h
+++ b/src/translator_hu.h
@@ -21,15 +21,32 @@
   *
   * Extended, revised and updated by
   * Ákos Kiss  <akiss@users.sourceforge.net>
+  *
+  * Further extended, revised and updated by
+  * Tamási Ferenc <tf551@hszk.bme.hu>
   */
 
 #ifndef TRANSLATOR_HU_H
 #define TRANSLATOR_HU_H
 
 #include "translator.h"
+#include "../qtools/qdatetime.h"
 
 class TranslatorHungarian : public Translator
 {
+  private:
+    const char * zed(char c)
+    {
+        switch (c & ~('a' ^ 'A')) {
+            case 'B': case 'C': case 'D': case 'F': case 'G':
+            case 'H': case 'J': case 'K': case 'L': case 'M':
+            case 'N': case 'P': case 'Q': case 'R': case 'S':
+            case 'T': case 'V': case 'W': case 'X': case 'Z':
+                return "  ";
+            default:
+                return "z ";
+        }
+    }
   public:
 
     // --- Language control methods -------------------
@@ -110,12 +127,9 @@ class TranslatorHungarian : public Translator
     QCString trIncludingInheritedMembers()
     { return " osztály tagjainak teljes listája, az örökölt tagokkal együtt."; }
     
-    /*! this is put at the author sections at the bottom of man pages.
-     *  parameter s is name of the project name.
-     */
     QCString trGeneratedAutomatically(const char *s)
     { QCString result="Ezt a dokumentációt a Doxygen készítette ";
-      if (s) result+=(QCString)" a(z) "+s+(QCString)" projekthez";
+      if (s) result+=(QCString)" a" + zed(s[0])+s+(QCString)" projekthez";
       result+=" a forráskódból."; 
       return result;
     }
@@ -512,7 +526,7 @@ class TranslatorHungarian : public Translator
     /*! this text is put before a class diagram */
     QCString trClassDiagram(const char *clName)
     {
-      return (QCString)"A(z) "+clName+" osztály származási diagramja:";
+      return (QCString)"A"+zed(clName[0])+clName+" osztály származási diagramja:";
     }
     
     /*! this text is generated when the \\internal command is used. */
@@ -835,12 +849,12 @@ class TranslatorHungarian : public Translator
     /*! this text is put before a collaboration diagram */
     QCString trCollaborationDiagram(const char *clName)
     {
-      return (QCString)"A(z) "+clName+" osztály együttmûködési diagramja:";
+      return (QCString)"A"+zed(clName[0])+clName+" osztály együttmûködési diagramja:";
     }
     /*! this text is put before an include dependency graph */
     QCString trInclDepGraph(const char *fName)
     {
-      return (QCString)"A(z) "+fName+" definíciós fájl függési gráfja:";
+      return (QCString)"A"+zed(fName[0])+fName+" definíciós fájl függési gráfja:";
     }
     /*! header that is put before the list of constructor/destructors. */
     QCString trConstructorDocumentation()
diff --git a/src/util.cpp b/src/util.cpp
index 5cc3ca8..c535634 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -368,12 +368,8 @@ QCString generateMarker(int id)
   return result;
 }
 
-/*! strip part of \a path if it matches
- *  one of the paths in the Config_getList("STRIP_FROM_PATH") list
- */
-QCString stripFromPath(const QCString &path)
+static QCString stripFromPath(const QCString &path,QStrList &l)
 {
-  QStrList &l = Config_getList("STRIP_FROM_PATH");
   const char *s=l.first();
   while (s)
   {
@@ -387,6 +383,22 @@ QCString stripFromPath(const QCString &path)
   return path;
 }
 
+/*! strip part of \a path if it matches
+ *  one of the paths in the Config_getList("STRIP_FROM_PATH") list
+ */
+QCString stripFromPath(const QCString &path)
+{
+  return stripFromPath(path,Config_getList("STRIP_FROM_PATH"));
+}
+
+/*! strip part of \a path if it matches
+ *  one of the paths in the Config_getList("INCLUDE_PATH") list
+ */
+QCString stripFromIncludePath(const QCString &path)
+{
+  return stripFromPath(path,Config_getList("STRIP_FROM_INC_PATH"));
+}
+
 /*! try to determine if \a name is a source or a header file name by looking
  * at the extension. A number of variations is allowed in both upper and 
  * lower case) If anyone knows or uses another extension please let me know :-)
@@ -759,19 +771,20 @@ bool accessibleViaUsingNamespace(const NamespaceSDict *nl,
  */
 int isAccessibleFrom(Definition *scope,FileDef *fileScope,Definition *item)
 {
-  //printf("<isAccesibleFrom(%s,%s)\n",scope->name().data(),item->name().data());
-  QCString key=scope->name()+"+"+item->name();
+  //fprintf(stderr,"<isAccesibleFrom(scope=%s,item=%s itemScope=%s)\n",
+  //    scope->name().data(),item->name().data(),item->getOuterScope()->name().data());
+  QCString key=scope->name()+"+"+item->qualifiedName();
   int *pval=g_accessibilityCache.find(key);
   int result=0; // assume we found it
   int i;
   if (pval) // value was cached
   {
-    //printf("> found cached value=%d\n",*pval);
+    //fprintf(stderr,"> found cached value=%d\n",*pval);
     return *pval; 
   }
   if (item->getOuterScope()==scope) 
   {
-    //printf("> found it\n");
+    //fprintf(stderr,"> found it\n");
   }
   else if (scope==Doxygen::globalScope)
   {
@@ -780,17 +793,17 @@ int isAccessibleFrom(Definition *scope,FileDef *fileScope,Definition *item)
       ClassSDict *cl = fileScope->getUsedClasses();
       if (accessibleViaUsingClass(cl,fileScope,item)) 
       {
-        //printf("> found via used class\n");
+        //fprintf(stderr,"> found via used class\n");
         goto done;
       }
       NamespaceSDict *nl = fileScope->getUsedNamespaces();
       if (accessibleViaUsingNamespace(nl,fileScope,item)) 
       {
-        //printf("> found via used namespace\n");
+        //fprintf(stderr,"> found via used namespace\n");
         goto done;
       }
     }
-    //printf("> reached global scope\n");
+    //fprintf(stderr,"> reached global scope\n");
     result=-1; // not found in path to globalScope
   }
   else // keep searching
@@ -802,19 +815,19 @@ int isAccessibleFrom(Definition *scope,FileDef *fileScope,Definition *item)
       ClassSDict *cl = nscope->getUsedClasses();
       if (accessibleViaUsingClass(cl,fileScope,item)) 
       {
-        //printf("> found via used class\n");
+        //fprintf(stderr,"> found via used class\n");
         goto done;
       }
       NamespaceSDict *nl = nscope->getUsedNamespaces();
       if (accessibleViaUsingNamespace(nl,fileScope,item)) 
       {
-        //printf("> found via used namespace\n");
+        //fprintf(stderr,"> found via used namespace\n");
         goto done;
       }
     }
     // repeat for the parent scope
     i=isAccessibleFrom(scope->getOuterScope(),fileScope,item);
-    //printf("> result=%d\n",i);
+    //fprintf(stderr,"> result=%d\n",i);
     result= (i==-1) ? -1 : i+1;
   }
 done:
@@ -838,7 +851,7 @@ int isAccessibleFrom(Definition *scope,FileDef *fileScope,Definition *item,
   //printf("<isAccesibleFrom(%s,%s,%s)\n",scope?scope->name().data():"<global>",
   //                                      item?item->name().data():"<none>",
   //                                      explicitScopePart.data());
-  QCString key=scope->name()+"+"+item->name()+"+"+explicitScopePart;
+  QCString key=scope->name()+"+"+item->qualifiedName()+"+"+explicitScopePart;
   int *pval=g_accessibilityCache.find(key);
   int result=0; // assume we found it
   if (pval) // value was cached
@@ -1019,6 +1032,7 @@ ClassDef *getResolvedClassRec(Definition *scope,
   {
     //printf("  found type %x name=%s\n",
     //       d->definitionType(),d->name().data());
+
     // only look at classes and members
     if (d->definitionType()==Definition::TypeClass ||
         d->definitionType()==Definition::TypeMember)
@@ -1042,9 +1056,10 @@ ClassDef *getResolvedClassRec(Definition *scope,
         else if (d->definitionType()==Definition::TypeMember)
         {
           MemberDef *md = (MemberDef *)d;
+          //printf("  member isTypedef()=%d\n",md->isTypedef());
           if (md->isTypedef()) // d is a typedef
           {
-            //printf("found typedef!\n");
+            //printf("    found typedef!\n");
             QCString spec;
             ClassDef *typedefClass = newResolveTypedef(fileScope,md,&spec);
 
@@ -1056,13 +1071,17 @@ ClassDef *getResolvedClassRec(Definition *scope,
             {
               minDistance=distance;
               bestMatch = typedefClass; 
-              //printf("bestTypeDef=%p\n",md);
+              //printf("      bestTypeDef=%p\n",md);
               bestTypedef = md;
               bestTemplSpec = spec;
             }
           }
         }
       } // if definition accessible
+      else
+      {
+        //printf("  Not accessible!\n");
+      }
     } // if definition is a class or member
   } // foreach definition
   if (pTypeDef) 
@@ -1683,6 +1702,11 @@ QCString yearToString()
 
 int minClassDistance(ClassDef *cd,ClassDef *bcd,int level)
 {
+  if (bcd->categoryOf()) // use class that is being extended in case of 
+                         // an Objective-C category
+  {
+    bcd=bcd->categoryOf();
+  }
   if (cd==bcd) return level; 
   if (level==256)
   {
@@ -3425,7 +3449,7 @@ QCString showFileDefMatches(const FileNameDict *fnDict,const char *n)
 
 //----------------------------------------------------------------------
 
-QCString substituteKeywords(const QCString &s,const char *title)
+QCString substituteKeywords(const QCString &s,const char *title,const QCString &relPath)
 {
   QCString result = s.copy();
   if (title) result = substitute(result,"$title",title);
@@ -3435,6 +3459,7 @@ QCString substituteKeywords(const QCString &s,const char *title)
   result = substitute(result,"$doxygenversion",versionString);
   result = substitute(result,"$projectname",Config_getString("PROJECT_NAME"));
   result = substitute(result,"$projectnumber",Config_getString("PROJECT_NUMBER"));
+  result = substitute(result,"$relpath$",relPath);
   return result;
 }
     
diff --git a/src/util.h b/src/util.h
index e27b75e..1ed34c5 100644
--- a/src/util.h
+++ b/src/util.h
@@ -154,9 +154,10 @@ QCString generateMarker(int id);
 void writeExample(OutputList &ol,ExampleSDict *el);
 QCString stripAnonymousNamespaceScope(const QCString &s);
 QCString stripFromPath(const QCString &path);
+QCString stripFromIncludePath(const QCString &path);
 bool rightScopeMatch(const QCString &scope, const QCString &name);
 bool leftScopeMatch(const QCString &scope, const QCString &name);
-QCString substituteKeywords(const QCString &s,const char *title);
+QCString substituteKeywords(const QCString &s,const char *title,const QCString &relPath="");
 int getPrefixIndex(const QCString &name);
 QCString removeAnonymousScopes(const QCString &s);
 QCString replaceAnonymousScopes(const QCString &s);
diff --git a/src/xmldocvisitor.cpp b/src/xmldocvisitor.cpp
index 5d50020..423da30 100644
--- a/src/xmldocvisitor.cpp
+++ b/src/xmldocvisitor.cpp
@@ -26,6 +26,7 @@
 #include "dot.h"
 #include "message.h"
 #include "util.h"
+#include <qfileinfo.h> 
 
 XmlDocVisitor::XmlDocVisitor(QTextStream &t,BaseCodeDocInterface &ci) 
   : DocVisitor(DocVisitor_XML), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE) 
@@ -213,6 +214,15 @@ void XmlDocVisitor::visit(DocInclude *inc)
   if (m_hide) return;
   switch(inc->type())
   {
+    case DocInclude::IncWithLines:
+      { 
+         m_t << "<programlisting>";
+         QFileInfo cfi( inc->file() );
+         FileDef fd( cfi.dirPath(), cfi.fileName() );
+         parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile(), &fd);
+         m_t << "</programlisting>"; 
+      }
+      break;    
     case DocInclude::Include: 
       m_t << "<programlisting>";
       parseCode(m_ci,inc->context(),inc->text().latin1(),inc->isExample(),inc->exampleFile());
diff --git a/src/xmlgen.cpp b/src/xmlgen.cpp
index f28bf7a..ef45139 100644
--- a/src/xmlgen.cpp
+++ b/src/xmlgen.cpp
@@ -590,6 +590,15 @@ static void generateXMLForMember(MemberDef *md,QTextStream &ti,QTextStream &t,De
 
     t << "\"";
   }
+  else if (md->memberType() == MemberDef::Property)
+  {
+    t << " readable=\"";
+    if (md->isReadable()) t << "yes"; else t << "no";
+    t << "\" writable=\"";
+    if (md->isWritable()) t << "yes"; else t << "no";
+    t << "\"";
+  }
+
 
   t << ">" << endl;
 
-- 
cgit v0.12

