You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4cxx-dev@logging.apache.org by ca...@apache.org on 2005/02/18 18:18:54 UTC

cvs commit: logging-log4cxx/tests/src/pattern num343patternconverter.cpp num343patternconverter.h patternparsertestcase.cpp

carnold     2005/02/18 09:18:54

  Modified:    .        build.xml
               include/log4cxx patternlayout.h
               include/log4cxx/helpers patternparser.h
               src      patternlayout.cpp patternparser.cpp timezone.cpp
               tests/input Makefile.am
               tests/src/helpers timezonetestcase.cpp
               tests/src/pattern num343patternconverter.cpp
                        num343patternconverter.h patternparsertestcase.cpp
  Log:
  LOGCXX-49: PatternParser refresh, timezones in patterns now supported
  
  Revision  Changes    Path
  1.44      +5 -3      logging-log4cxx/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/build.xml,v
  retrieving revision 1.43
  retrieving revision 1.44
  diff -u -r1.43 -r1.44
  --- build.xml	17 Feb 2005 00:55:34 -0000	1.43
  +++ build.xml	18 Feb 2005 17:18:53 -0000	1.44
  @@ -518,8 +518,7 @@
           <foreach target="make-header-check" param="header">
                   <path><fileset dir="${build.dir}/header-check" includes="**/*.h"/></path>
           </foreach>
  -        <mkdir dir="${obj.dir}/header-check"/>
  -        <cc objdir="${obj.dir}/header-check"
  +        <cc objdir="${build.dir}/header-check"
                   name="gcc"
                   exceptions="true"
                   subsystem="gui"
  @@ -1033,6 +1032,9 @@
               <include name="tests/witness/*"/>
               <include name="tests/witness/ndc/*"/>
               <include name="tests/log4j.dtd"/>
  +            <include name="**/*.am"/>
  +            <include name="**/*.in"/>
  +            <include name="**/*.patch"/>
               <exclude name="**/.cvsignore"/>
           </tarfileset>
       </tar>
  @@ -1042,7 +1044,7 @@
   
   <target name="fixcrlf" depends="init" description="repair end-of-line sequences">
      <fixcrlf srcDir="${base.dir}" tab="remove" tablength="3"
  -       fixlast="true" includes="**/*.cpp **/*.h" excludes="lib/**/*"/>
  +       eof="remove" fixlast="true" includes="**/*.cpp **/*.h" excludes="lib/**/*"/>
   </target>
   
   </project>
  
  
  
  1.21      +1 -14     logging-log4cxx/include/log4cxx/patternlayout.h
  
  Index: patternlayout.h
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/include/log4cxx/patternlayout.h,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- patternlayout.h	26 Dec 2004 07:31:52 -0000	1.20
  +++ patternlayout.h	18 Feb 2005 17:18:53 -0000	1.21
  @@ -1,5 +1,5 @@
   /*
  - * Copyright 2003,2004 The Apache Software Foundation.
  + * Copyright 2003,2005 The Apache Software Foundation.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
  @@ -383,7 +383,6 @@
                   LogString sbuf;
                   LogString pattern;
                   helpers::PatternConverterPtr head;
  -                LogString timeZone;
   
           public:
                   DECLARE_LOG4CXX_OBJECT(PatternLayout)
  @@ -436,18 +435,6 @@
                   virtual void format(LogString& output,
                        const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& pool) const;
   
  -                /**
  -                The <b>TimeZoneID</b> option is a time zone ID string in the format
  -                expected by the <code>locale</code> C++ standard class.
  -                */
  -                inline void setTimeZone(const LogString& timeZone)
  -                        { this->timeZone.assign(timeZone); }
  -
  -                /**
  -                Returns value of the <b>TimeZone</b> option.
  -                */
  -                inline const LogString& getTimeZone() const
  -                        { return timeZone; }
   
           protected:
                   /**
  
  
  
  1.20      +131 -95   logging-log4cxx/include/log4cxx/helpers/patternparser.h
  
  Index: patternparser.h
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/include/log4cxx/helpers/patternparser.h,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- patternparser.h	15 Feb 2005 23:55:59 -0000	1.19
  +++ patternparser.h	18 Feb 2005 17:18:53 -0000	1.20
  @@ -1,5 +1,5 @@
   /*
  - * Copyright 2003,2004 The Apache Software Foundation.
  + * Copyright 2003,2005 The Apache Software Foundation.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
  @@ -22,6 +22,29 @@
   #include <log4cxx/helpers/objectimpl.h>
   #include <log4cxx/helpers/formattinginfo.h>
   #include <log4cxx/helpers/patternconverter.h>
  +#include <log4cxx/helpers/dateformat.h>
  +#include <log4cxx/helpers/relativetimedateformat.h>
  +#include <map>
  +#include <vector>
  +
  +#define DEFINE_PATTERN_CONVERTER(classname)                   \
  +class LOG4CXX_EXPORT classname : public PatternConverter {    \
  +public:                                                       \
  +classname(const FormattingInfo& formattingInfo,               \
  +          const std::vector<LogString>& options);             \
  +virtual void convert(LogString& sbuf,                         \
  +              const spi::LoggingEventPtr& event,              \
  +              log4cxx::helpers::Pool& pool) const;            \
  +static PatternConverter* newInstance(                         \
  +          const FormattingInfo& formattingInfo,               \
  +          const std::vector<LogString>& options) {            \
  +          return new classname(formattingInfo, options);  }   \
  +private:                                                      \
  +classname(const classname&);                                  \
  +classname& operator=(const classname&);                       \
  +
  +#define END_DEFINE_PATTERN_CONVERTER(classname)          };
  +
   
   namespace log4cxx
   {
  @@ -45,133 +68,146 @@
           */
                   class LOG4CXX_EXPORT PatternParser
                   {
  -                protected:
  -                        int state;
  -                        LogString currentLiteral;
  -                        size_t patternLength;
  -                        size_t i;
  -                        PatternConverterPtr head;
  -                        PatternConverterPtr tail;
  -                        FormattingInfo formattingInfo;
  -                        LogString pattern;
  -                        LogString timeZone;
  +                public:
  +                typedef PatternConverter* (*PatternConverterFactory)(
  +                     const FormattingInfo& info,
  +                     const std::vector<LogString>& options);
  +                typedef std::map<LogString, PatternConverterFactory> PatternConverterMap;
  +
  +                private:
  +                  enum {
  +                      LITERAL_STATE = 0,
  +                      CONVERTER_STATE = 1,
  +                      MINUS_STATE = 2,
  +                      DOT_STATE = 3,
  +                      MIN_STATE = 4,
  +                      MAX_STATE = 5 } state;
  +
  +                  static const PatternConverterMap& getGlobalRulesRegistry();
  +
  +                  LogString currentLiteral;
  +                  int patternLength;
  +                  int i;
  +                  PatternConverterPtr head;
  +                  PatternConverterPtr tail;
  +                  FormattingInfo formattingInfo;
  +                  LogString pattern;
  +
  +                  /**
  +                   * Additional rules for this particular instance.
  +                   * key: the conversion word (as String)
  +                   * value: the pattern converter class (as String)
  +                   */
  +                  PatternConverterMap converterRegistry;
  +
  +
   
                   public:
  -                        PatternParser(const LogString& pattern, const LogString& timeZone);
  +                        PatternParser(const LogString& pattern);
   
                   private:
                           void addToList(PatternConverterPtr& pc);
  +                        LogString extractConverter(logchar lastChar);
  +                        std::vector<LogString> extractOptions();
   
  -                protected:
  -                        LogString extractOption();
  -
  -                        /**
  -                        The option is expected to be in decimal and positive. In case of
  -                        error, zero is returned.  */
  -                        int extractPrecisionOption();
   
                   public:
                           PatternConverterPtr parse();
   
  -                protected:
  +                        PatternConverterMap getConverterRegistry() const;
  +                        void setConverterRegistry(const PatternConverterMap&);
  +
  +
  +                private:
  +                        PatternConverterFactory findConverterClass(const LogString& converterId);
  +
                           void finalizeConverter(logchar c);
   
                           void addConverter(PatternConverterPtr& pc);
   
  +                        bool isUnicodeIdentifierStart(logchar ch);
  +                        bool isUnicodeIdentifierPart(logchar ch);
  +
  +                        static void logError(const LogString& msg);
  +                        static void logWarn(const LogString& msg);
  +                        static int getPrecision(const std::vector<LogString>& options);
  +
  +
                   // ---------------------------------------------------------------------
                   //                      PatternConverters
                   // ---------------------------------------------------------------------
                   private:
  -                        class LOG4CXX_EXPORT BasicPatternConverter : public PatternConverter
  -                        {
  -                        private:
  -                                int type;
  -                        public:
  -                                BasicPatternConverter(const FormattingInfo& formattingInfo, int type);
  -                                virtual void convert(LogString& sbuf,
  -                                        const spi::LoggingEventPtr& event,
  -                                        log4cxx::helpers::Pool& pool) const;
  -                        };
  -
  -                        class LOG4CXX_EXPORT LiteralPatternConverter : public PatternConverter
  -                        {
  -                        private:
  -                                LogString literal;
   
  +                        class LOG4CXX_EXPORT LiteralPatternConverter : public PatternConverter {
                           public:
  -                                LiteralPatternConverter(const LogString& value);
  -                                virtual void convert(LogString& sbuf,
  -                                        const spi::LoggingEventPtr& event,
  -                                        log4cxx::helpers::Pool& pool) const;
  +                            LiteralPatternConverter(const LogString& literal);
  +                            virtual void convert(LogString& sbuf,
  +                                      const spi::LoggingEventPtr& event,
  +                                      log4cxx::helpers::Pool& pool) const;
                           private:
  -                                //   prevent copy and assignment
  -                                LiteralPatternConverter(const LiteralPatternConverter&);
  -                                LiteralPatternConverter& operator=(const LiteralPatternConverter&);
  +                            LiteralPatternConverter(LiteralPatternConverter&);
  +                            LiteralPatternConverter& operator=(LiteralPatternConverter&);
  +                            LogString literal;
                           };
   
  -                        class LOG4CXX_EXPORT DatePatternConverter : public PatternConverter
  -                        {
  -                        private:
  -                                DateFormat * df;
   
  -                        public:
  -                                DatePatternConverter(const FormattingInfo& formattingInfo,
  -                                        DateFormat * df);
  -                                ~DatePatternConverter();
  -
  -                                virtual void convert(LogString& sbuf,
  -                                        const spi::LoggingEventPtr& event,
  -                                        log4cxx::helpers::Pool& pool) const;
  +                        DEFINE_PATTERN_CONVERTER(DatePatternConverter)
  +                            DateFormatPtr df;
  +                            static DateFormatPtr createDateFormat(const std::vector<LogString>& options);
  +                        END_DEFINE_PATTERN_CONVERTER(DatePatternConverter)
   
  -                        private:
  -                                //   prevent copy and assignment
  -                                DatePatternConverter(const DatePatternConverter&);
  -                                DatePatternConverter& operator=(const DatePatternConverter&);
  -                        };
  +                        DEFINE_PATTERN_CONVERTER(FullLocationPatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(FullLocationPatternConverter)
   
  -                        class LOG4CXX_EXPORT MDCPatternConverter : public PatternConverter
  -                        {
  -                        private:
  -                                LogString key;
  +                        DEFINE_PATTERN_CONVERTER(LineLocationPatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(LineLocationPatternConverter)
   
  -                        public:
  -                                MDCPatternConverter(const FormattingInfo& formattingInfo,
  -                                        const LogString& key);
  -                                virtual void convert(LogString& sbuf,
  -                                        const spi::LoggingEventPtr& event,
  -                                        log4cxx::helpers::Pool& pool) const;
  -                        private:
  -                                //   prevent copy and assignment
  -                                MDCPatternConverter(const MDCPatternConverter&);
  -                                MDCPatternConverter& operator=(const MDCPatternConverter&);
  -                        };
  +                        DEFINE_PATTERN_CONVERTER(FileLocationPatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(FileLocationPatternConverter)
   
  -                        class LOG4CXX_EXPORT LocationPatternConverter : public PatternConverter
  -                        {
  -                        private:
  -                                int type;
  +                        DEFINE_PATTERN_CONVERTER(MethodLocationPatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(MethodLocationPatternConverter)
   
  -                        public:
  -                                LocationPatternConverter(const FormattingInfo& formattingInfo, int type);
  -                                virtual void convert(LogString& sbuf,
  -                                        const spi::LoggingEventPtr& event,
  -                                        log4cxx::helpers::Pool& pool) const;
  -                        };
  +                        DEFINE_PATTERN_CONVERTER(ClassNamePatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(ClassNamePatternConverter)
  +
  +                        DEFINE_PATTERN_CONVERTER(LoggerPatternConverter)
  +                            int precision;
  +                        END_DEFINE_PATTERN_CONVERTER(LoggerPatternConverter)
  +
  +                        DEFINE_PATTERN_CONVERTER(MessagePatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(MessagePatternConverter)
  +
  +                        DEFINE_PATTERN_CONVERTER(LineSeparatorPatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(LineSeparatorPatternConverter)
  +
  +                        DEFINE_PATTERN_CONVERTER(LevelPatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(LevelPatternConverter)
  +
  +                        DEFINE_PATTERN_CONVERTER(RelativeTimePatternConverter)
  +                            RelativeTimeDateFormat formatter;
  +                        END_DEFINE_PATTERN_CONVERTER(RelativeTimePatternConverter)
  +
  +                        DEFINE_PATTERN_CONVERTER(ThreadPatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(ThreadPatternConverter)
  +
  +                        DEFINE_PATTERN_CONVERTER(NDCPatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(NDCPatternConverter)
  +
  +                        DEFINE_PATTERN_CONVERTER(PropertiesPatternConverter)
  +                          LogString key;
  +                          static LogString getKey(const std::vector<LogString>& options);
  +                        END_DEFINE_PATTERN_CONVERTER(PropertiesPatternConverter)
  +
  +                        DEFINE_PATTERN_CONVERTER(ThrowableInformationPatternConverter)
  +                        END_DEFINE_PATTERN_CONVERTER(ThrowableInformationPatternConverter)
   
  -                        class LOG4CXX_EXPORT CategoryPatternConverter : public PatternConverter
  -                        {
  -                        private:
  -                                int precision;
   
  -                        public:
  -                                CategoryPatternConverter(const FormattingInfo& formattingInfo,
  -                                        int precision);
  -                                virtual void convert(LogString& sbuf,
  -                                        const spi::LoggingEventPtr& event,
  -                                        log4cxx::helpers::Pool& pool) const;
  -                        };
                   }; // class PatternParser
           }  // namespace helpers
   } // namespace log4cxx
   
  +#undef DEFINE_PATTERN_CONVERTER
  +#undef END_DEFINE_PATTERN_CONVERTER
  +
   #endif //_LOG4CXX_HELPER_PATTERN_PARSER_H
  
  
  
  1.17      +1 -7      logging-log4cxx/src/patternlayout.cpp
  
  Index: patternlayout.cpp
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/src/patternlayout.cpp,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- patternlayout.cpp	15 Feb 2005 23:56:01 -0000	1.16
  +++ patternlayout.cpp	18 Feb 2005 17:18:53 -0000	1.17
  @@ -68,7 +68,7 @@
   
   PatternConverterPtr PatternLayout::createPatternParser(const LogString& pattern)
   {
  -        return PatternParser(pattern, timeZone).parse();
  +        return PatternParser(pattern).parse();
   }
   
   void PatternLayout::setOption(const LogString& option, const LogString& value)
  @@ -79,12 +79,6 @@
           {
                   pattern = OptionConverter::convertSpecialChars(value);
           }
  -        else if (StringHelper::equalsIgnoreCase(option,
  -               LOG4CXX_STR("TIMEZONE"),
  -               LOG4CXX_STR("timezone")))
  -        {
  -                timeZone = value;
  -        }
   }
   
   void PatternLayout::activateOptions(Pool& p)
  
  
  
  1.29      +560 -362  logging-log4cxx/src/patternparser.cpp
  
  Index: patternparser.cpp
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/src/patternparser.cpp,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- patternparser.cpp	15 Feb 2005 23:56:01 -0000	1.28
  +++ patternparser.cpp	18 Feb 2005 17:18:53 -0000	1.29
  @@ -26,6 +26,7 @@
   #include <log4cxx/level.h>
   #include <log4cxx/mdc.h>
   #include <log4cxx/helpers/transcoder.h>
  +#include <sstream>
   
   #include <apr_pools.h>
   
  @@ -35,43 +36,105 @@
   
   #define ESCAPE_CHAR LOG4CXX_STR('%')
   
  -enum ParserState
  -{
  -        LITERAL_STATE,
  -        CONVERTER_STATE,
  -        MINUS_STATE,
  -        DOT_STATE,
  -        MIN_STATE,
  -        MAX_STATE,
  -
  -        FULL_LOCATION_CONVERTER,
  -        //METHOD_LOCATION_CONVERTER = 1001;
  -        CLASS_LOCATION_CONVERTER,
  -        LINE_LOCATION_CONVERTER,
  -        FILE_LOCATION_CONVERTER,
  -
  -        RELATIVE_TIME_CONVERTER,
  -        THREAD_CONVERTER,
  -        LEVEL_CONVERTER,
  -        NDC_CONVERTER,
  -        MESSAGE_CONVERTER
  -};
  +const PatternParser::PatternConverterMap& PatternParser::getGlobalRulesRegistry() {
  +  static PatternConverterMap globalRulesRegistry;
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("c"),
  +      LoggerPatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("logger"),
  +      LoggerPatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("C"),
  +      ClassNamePatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("class"),
  +      ClassNamePatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("d"),
  +      DatePatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("date"),
  +      DatePatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("F"),
  +     FileLocationPatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("file"),
  +     FileLocationPatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("l"),
  +     FullLocationPatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("L"),
  +     LineLocationPatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("line"),
  +     LineLocationPatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("m"),
  +     MessagePatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("message"),
  +     MessagePatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("n"),
  +     LineSeparatorPatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(
  +    PatternConverterMap::value_type(LOG4CXX_STR("M"),
  +    MethodLocationPatternConverter::newInstance));
  +  globalRulesRegistry.insert(
  +    PatternConverterMap::value_type(LOG4CXX_STR("method"),
  +    MethodLocationPatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("p"),
  +      LevelPatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("level"),
  +      LevelPatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("r"),
  +     RelativeTimePatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("relative"),
  +     RelativeTimePatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("t"),
  +     ThreadPatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("thread"),
  +     ThreadPatternConverter::newInstance));
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("x"),
  +     NDCPatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("ndc"),
  +     NDCPatternConverter::newInstance));
   
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("X"),
  +     PropertiesPatternConverter::newInstance));
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("properties"),
  +     PropertiesPatternConverter::newInstance));
   
  -PatternParser::PatternParser(const LogString& pattern, const LogString& timeZone)
  +
  +  globalRulesRegistry.insert(PatternConverterMap::value_type(LOG4CXX_STR("throwable"),
  +     ThrowableInformationPatternConverter::newInstance));
  +
  +  return globalRulesRegistry;
  +}
  +
  +void PatternParser::logError(const LogString& msg) {
  +  LogLog::error(msg);
  +}
  +
  +void PatternParser::logWarn(const LogString& msg) {
  +  LogLog::warn(msg);
  +}
  +
  +
  +PatternParser::PatternParser(const LogString& pattern)
   :
      state(LITERAL_STATE),
  -   currentLiteral(),
      patternLength(pattern.length()),
      i(0),
      head(),
      tail(),
      formattingInfo(),
  -   pattern(pattern),
  -   timeZone(timeZone)
  +   pattern(pattern)
   {
   }
   
  +
   void PatternParser::addToList(PatternConverterPtr& pc)
   {
           if(head == 0)
  @@ -85,305 +148,258 @@
           }
   }
   
  -LogString PatternParser::extractOption()
  -{
  -        if((i < patternLength) && (pattern.at(i) == LOG4CXX_STR('{')))
  -        {
  -                size_t end = pattern.find(LOG4CXX_STR('}'), i);
  -                if (end > i)
  -                {
  -                        LogString r = pattern.substr(i + 1, end - (i + 1));
  -                        i = end+1;
  -                        return r;
  -                }
  -        }
  +bool PatternParser::isUnicodeIdentifierStart(logchar ch) {
  +  //
  +  //   greatly simplified version checks if
  +  //     character is USACII alpha or number
  +  //
  +  return (ch >= LOG4CXX_STR('A') && ch <= LOG4CXX_STR('Z')) ||
  +         (ch >= LOG4CXX_STR('a') && ch <= LOG4CXX_STR('z')) ||
  +         (ch >= LOG4CXX_STR('0') && ch <= LOG4CXX_STR('9'));
  +}
   
  -        return LogString();
  +bool PatternParser::isUnicodeIdentifierPart(logchar ch) {
  +  //
  +  //   greatly simplified version checks if
  +  //     character is USACII alpha or number
  +  //
  +  return (ch >= LOG4CXX_STR('A') && ch <= LOG4CXX_STR('Z')) ||
  +         (ch >= LOG4CXX_STR('a') && ch <= LOG4CXX_STR('z')) ||
  +         (ch >= LOG4CXX_STR('0') && ch <= LOG4CXX_STR('9')) ||
  +         (ch == LOG4CXX_STR('_'));
   }
   
  -int PatternParser::extractPrecisionOption()
  -{
  -        LogString opt = extractOption();
  -        int r = 0;
  -        if(!opt.empty())
  -        {
  -                r = StringHelper::toInt(opt);
  -                if(r <= 0)
  -                {
  -                        LogLog::error(
  -                                ((LogString) LOG4CXX_STR("Precision option ("))
  -                                 + opt + LOG4CXX_STR(") isn't a positive integer."));
  -                        r = 0;
  -                }
  -        }
  -        return r;
  +/** Extract the converter identifier found at position i.
  + *
  + * After this function returns, the variable i will point to the
  + * first char after the end of the converter identifier.
  + *
  + * If i points to a char which is not a character acceptable at the
  + * start of a unicode identifier, the value null is returned.
  + *
  + */
  +LogString PatternParser::extractConverter(logchar lastChar) {
  +
  +  // When this method is called, lastChar points to the first character of the
  +  // conersion word. For example:
  +  // For "%hello"     lastChar = 'h'
  +  // For "%-5hello"   lastChar = 'h'
  +
  +        //System.out.println("lastchar is "+lastChar);
  +
  +  if(!isUnicodeIdentifierStart(lastChar)) {
  +    return LogString();
  +  }
  +
  +  LogString convBuf(1, lastChar);
  +
  +  while ((i < patternLength)
  +                && isUnicodeIdentifierPart(pattern.at(i))) {
  +    convBuf.append(1, pattern.at(i));
  +    i++;
  +  }
  +
  +  return convBuf;
   }
   
  -PatternConverterPtr PatternParser::parse()
  +
  +std::vector<LogString>  PatternParser::extractOptions()
   {
  -        logchar c;
  -        i = 0;
  -        while(i < patternLength)
  -        {
  -                c = pattern.at(i++);
  -                switch(state)
  -                {
  -                case LITERAL_STATE:
  -                        // In literal state, the last char is always a literal.
  -                        if(i == patternLength)
  -                        {
  -                                currentLiteral.append(1, c);
  -                                continue;
  -                        }
  -                        if(c == ESCAPE_CHAR)
  -                        {
  -                                // peek at the next char.
  -                                switch(pattern.at(i))
  -                                {
  -                                case ESCAPE_CHAR:
  -                                        currentLiteral.append(1, c);
  -                                        i++; // move pointer
  -                                        break;
  -                                case LOG4CXX_STR('n'):
  -#if defined(_WIN32)
  -                                        currentLiteral.append(LOG4CXX_STR("\x0D\x0A"));
  -#else
  -                                        currentLiteral.append(1, LOG4CXX_STR('\x0A'));
  -#endif
  -                                        i++; // move pointer
  -                                        break;
  -                                default:
  -                                        // test if currentLiteral is not empty
  -                                        if(!currentLiteral.empty())
  -                                        {
  -                                                PatternConverterPtr patternConverter(new LiteralPatternConverter(
  -                                                        currentLiteral));
  -                                                addToList(patternConverter);
  -                                                //LogLog.debug("Parsed LITERAL converter: \""
  -                                                //           +currentLiteral+"\".");
  -                                        }
  -                                        currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                                        currentLiteral.append(1, c); // append %
  -                                        state = CONVERTER_STATE;
  -                                        formattingInfo.reset();
  -                                }
  -                        }
  -                        else
  -                        {
  -                                currentLiteral.append(1, c);
  -                        }
  -                        break;
  -                case CONVERTER_STATE:
  -                        currentLiteral.append(1, c);
  -                        switch(c)
  -                        {
  -                        case LOG4CXX_STR('-'):
  -                                formattingInfo.leftAlign = true;
  -                                break;
  -                        case LOG4CXX_STR('.'):
  -                                state = DOT_STATE;
  -                                break;
  -                        default:
  -                                if(c >= LOG4CXX_STR('0') && c <= LOG4CXX_STR('9'))
  -                                {
  -                                        formattingInfo.minChar = c - LOG4CXX_STR('0');
  -                                        state = MIN_STATE;
  -                                }
  -                                else
  -                                        finalizeConverter(c);
  -                        } // switch
  -                        break;
  -                        case MIN_STATE:
  -                                currentLiteral.append(1, c);
  -                                if(c >= LOG4CXX_STR('0') && c <= LOG4CXX_STR('9'))
  -                                        formattingInfo.minChar = formattingInfo.minChar*10 + (c - LOG4CXX_STR('0'));
  -                                else if(c == LOG4CXX_STR('.'))
  -                                        state = DOT_STATE;
  -                                else
  -                                {
  -                                        finalizeConverter(c);
  -                                }
  -                                break;
  -                        case DOT_STATE:
  -                                currentLiteral.append(1, c);
  -                                if(c >= LOG4CXX_STR('0') && c <= LOG4CXX_STR('9'))
  -                                {
  -                                        formattingInfo.maxChar = c - LOG4CXX_STR('0');
  -                                        state = MAX_STATE;
  -                                }
  -                                else {
  -                                        Pool p;
  -                                        LogLog::error(((LogString) LOG4CXX_STR("Error occured in position "))
  -                                                + StringHelper::toString(i, p)
  -                                                + LOG4CXX_STR(".") LOG4CXX_EOL LOG4CXX_STR(" Was expecting digit, instead got char \"")
  -                                                + LogString(1, c)
  -                                                + LOG4CXX_STR("\"."));
  -                                        state = LITERAL_STATE;
  -                                }
  -                                break;
  -                        case MAX_STATE:
  -                                currentLiteral.append(1, c);
  -                                if(c >= LOG4CXX_STR('0') && c <= LOG4CXX_STR('9'))
  -                                        formattingInfo.maxChar = formattingInfo.maxChar*10 + (c - LOG4CXX_STR('0'));
  -                                else
  -                                {
  -                                        finalizeConverter(c);
  -                                        state = LITERAL_STATE;
  -                                }
  -                                break;
  -                } // switch
  -        } // while
  -        // test if currentLiteral is not empty
  -        if(!currentLiteral.empty())
  -        {
  -                PatternConverterPtr patternConverter(
  -                        new LiteralPatternConverter(currentLiteral));
  -                addToList(patternConverter);
  -                //LogLog.debug("Parsed LITERAL converter: \""+currentLiteral+"\".");
  -        }
  -        return head;
  +  std::vector<LogString> options;
  +  while ((i < patternLength) && (pattern.at(i) == LOG4CXX_STR('{'))) {
  +    size_t end = pattern.find(LOG4CXX_STR('}'), i);
  +
  +    if (end > i) {
  +      LogString r(pattern.substr(i + 1, end - (i + 1)));
  +      options.push_back(r);
  +       i = end+1;
  +    }
  +  }
  +
  +  return options;
   }
   
  -void PatternParser::finalizeConverter(logchar c)
  -{
  -        PatternConverterPtr pc;
  +PatternConverterPtr PatternParser::parse() {
  +    logchar c;
  +    i = 0;
   
  -        switch(c)
  -        {
  -        case LOG4CXX_STR('c'):
  -                pc = new CategoryPatternConverter(formattingInfo,
  -                        extractPrecisionOption());
  -                //LogLog::debug(LOG4CXX_STR("CATEGORY converter."));
  -                //formattingInfo.dump();
  -                currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                break;
  -        case LOG4CXX_STR('d'):
  -        {
  -                DateFormat * df = 0;
  -                LogString dateFormatStr(extractOption());
  -                if(dateFormatStr.empty() ||
  -                        StringHelper::equalsIgnoreCase(dateFormatStr,
  -                        LOG4CXX_STR("ISO8601"), LOG4CXX_STR("iso8601")))
  -                        df = new ISO8601DateFormat();
  -                else if(StringHelper::equalsIgnoreCase(dateFormatStr,
  -                        LOG4CXX_STR("ABSOLUTE"), LOG4CXX_STR("absolute")))
  -                        df = new AbsoluteTimeDateFormat();
  -                else if(StringHelper::equalsIgnoreCase(dateFormatStr,
  -                        LOG4CXX_STR("DATE"), LOG4CXX_STR("date")))
  -                        df = new DateTimeDateFormat();
  -                else
  -                {
  -                        if (dateFormatStr.find(LOG4CXX_STR('%')) == std::string::npos) {
  -                            df = new SimpleDateFormat(dateFormatStr);
  -                        } else {
  -                                df = new StrftimeDateFormat(dateFormatStr);
  -                        }
  -                }
  -                DateFormatPtr formatter(df);
  -                df = new CachedDateFormat(formatter);
  -                pc = new DatePatternConverter(formattingInfo, df);
  -                //LogLog.debug("DATE converter {"+dateFormatStr+"}.");
  -                //formattingInfo.dump();
  -                currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                break;
  -        }
  -        case LOG4CXX_STR('F'):
  -                pc = new LocationPatternConverter(formattingInfo,
  -                        FILE_LOCATION_CONVERTER);
  -                //LogLog.debug("File name converter.");
  -                //formattingInfo.dump();
  -                currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                break;
  -        case LOG4CXX_STR('l'):
  -                pc = new LocationPatternConverter(formattingInfo,
  -                        FULL_LOCATION_CONVERTER);
  -                //LogLog.debug("Location converter.");
  -                //formattingInfo.dump();
  -                currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                break;
  -        case LOG4CXX_STR('L'):
  -
  -                pc = new LocationPatternConverter(formattingInfo,
  -                        LINE_LOCATION_CONVERTER);
  -                //LogLog.debug("LINE NUMBER converter.");
  -                //formattingInfo.dump();
  -                currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                break;
  -        case LOG4CXX_STR('m'):
  -                pc = new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER);
  -                //LogLog.debug("MESSAGE converter.");
  -                //formattingInfo.dump();
  -                currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                break;
  -        case LOG4CXX_STR('p'):
  -                {
  -                pc = new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER);
  -                //LogLog.debug("LEVEL converter.");
  -                //formattingInfo.dump();
  -        currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                }
  -                break;
  -        case LOG4CXX_STR('r'):
  -                pc = new BasicPatternConverter(formattingInfo,
  -                        RELATIVE_TIME_CONVERTER);
  -                //LogLog.debug("RELATIVE time converter.");
  -                //formattingInfo.dump();
  -                currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                break;
  -
  -        case LOG4CXX_STR('t'):
  -                pc = new BasicPatternConverter(formattingInfo, THREAD_CONVERTER);
  -                //LogLog.debug("THREAD converter.");
  -                //formattingInfo.dump();
  -        currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                break;
  +    while (i < patternLength) {
  +      c = pattern.at(i++);
   
  +      switch (state) {
  +      case LITERAL_STATE:
   
  -                /*case 'u':
  -                if(i < patternLength) {
  -                char cNext = pattern.charAt(i);
  -                if(cNext >= '0' && cNext <= '9') {
  -                pc = new UserFieldPatternConverter(formattingInfo, cNext - '0');
  -                LogLog.debug("USER converter ["+cNext+"].");
  -                formattingInfo.dump();
  -                currentLiteral.setLength(0);
  -                i++;
  -                }
  -                else
  -                LogLog.error("Unexpected char" +cNext+" at position "+i);
  -                }
  -                break;*/
  +        // In literal state, the last char is always a literal.
  +        if (i == patternLength) {
  +          currentLiteral.append(1, c);
  +
  +          continue;
  +        }
   
  -        case LOG4CXX_STR('x'):
  -                pc = new BasicPatternConverter(formattingInfo, NDC_CONVERTER);
  -                //LogLog.debug("NDC converter.");
  -                currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                break;
  +        if (c == ESCAPE_CHAR) {
  +          // peek at the next char.
  +          switch (pattern.at(i)) {
  +          case ESCAPE_CHAR:
  +            currentLiteral.append(1, c);
  +            i++; // move pointer
   
  -        case LOG4CXX_STR('X'):
  -        {
  -                LogString xOpt = extractOption();
  -                pc = new MDCPatternConverter(formattingInfo, xOpt);
  -                currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -                break;
  +            break;
  +
  +          default:
  +
  +            if (currentLiteral.length() != 0) {
  +              PatternConverterPtr converter(
  +                new LiteralPatternConverter(currentLiteral));
  +              addToList(converter);
  +
  +            }
  +
  +            currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  +            currentLiteral.append(1, c); // append %
  +            state = CONVERTER_STATE;
  +            formattingInfo.reset();
  +          }
  +        } else {
  +          currentLiteral.append(1, c);
           }
   
  +        break;
  +
  +      case CONVERTER_STATE:
  +        currentLiteral.append(1, c);
  +
  +        switch (c) {
  +        case '-':
  +          formattingInfo.leftAlign = true;
  +
  +          break;
  +
  +        case '.':
  +          state = DOT_STATE;
  +
  +          break;
  +
           default:
  -        {
  -                Pool p;
  -                LogLog::error(((LogString) LOG4CXX_STR("Unexpected char ["))
  -                        + LogString(1, c)
  -                        + LOG4CXX_STR("] at position ")
  -                        + StringHelper::toString(i, p)
  -                        + LOG4CXX_STR(" in conversion pattern."));
  -                pc = new LiteralPatternConverter(currentLiteral);
  -                currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  -        }
  -        }
   
  -        addConverter(pc);
  +          if ((c >= LOG4CXX_STR('0')) && (c <= LOG4CXX_STR('9'))) {
  +            formattingInfo.minChar = c - LOG4CXX_STR('0');
  +            state = MIN_STATE;
  +          } else {
  +            finalizeConverter(c);
  +          }
  +        } // switch
  +
  +        break;
  +
  +      case MIN_STATE:
  +        currentLiteral.append(1, c);
  +
  +        if ((c >= LOG4CXX_STR('0')) && (c <= LOG4CXX_STR('9'))) {
  +          formattingInfo.minChar = (formattingInfo.minChar * 10) + (c - LOG4CXX_STR('0'));
  +        } else if (c == LOG4CXX_STR('.')) {
  +          state = DOT_STATE;
  +        } else {
  +          finalizeConverter(c);
  +        }
  +
  +        break;
  +
  +      case DOT_STATE:
  +        currentLiteral.append(1, c);
  +
  +        if ((c >= LOG4CXX_STR('0')) && (c <= LOG4CXX_STR('9'))) {
  +          formattingInfo.maxChar = c - LOG4CXX_STR('0');
  +          state = MAX_STATE;
  +        } else {
  +          std::basic_ostringstream<logchar> os;
  +          os << LOG4CXX_STR("Error occured in position ") << i
  +             << LOG4CXX_STR(".\n Was expecting digit, instead got char \"")
  +             << c + LOG4CXX_STR("\".");
  +          logError(os.str());
  +          state = LITERAL_STATE;
  +        }
  +
  +        break;
  +
  +      case MAX_STATE:
  +        currentLiteral.append(1, c);
  +
  +        if ((c >= LOG4CXX_STR('0')) && (c <= LOG4CXX_STR('9'))) {
  +          formattingInfo.maxChar = (formattingInfo.maxChar * 10) + (c - LOG4CXX_STR('0'));
  +        } else {
  +          finalizeConverter(c);
  +          state = LITERAL_STATE;
  +        }
  +
  +        break;
  +      } // switch
  +    }
  +
  +    // while
  +    if (currentLiteral.length() != 0) {
  +      PatternConverterPtr converter(new LiteralPatternConverter(currentLiteral));
  +      addToList(converter);
  +
  +      //LogLog.debug("Parsed LITERAL converter: \""+currentLiteral+"\".");
  +    }
  +
  +    return head;
  +  }
  +
  +PatternParser::PatternConverterFactory PatternParser::findConverterClass(
  +     const LogString& converterId) {
  +
  +    PatternConverterMap::const_iterator r = converterRegistry.find(converterId);
  +    if(r != converterRegistry.end()) {
  +       return r->second;
  +    }
  +
  +    r = getGlobalRulesRegistry().find(converterId);
  +    if(r != getGlobalRulesRegistry().end()) {
  +       return r->second;
  +    }
  +
  +    return NULL;
  +}
  +
  +
  +/**
  + * When finalizeConverter is called 'c' is the current conversion caracter
  + * and i points to the character following 'c'.
  + */
  +void PatternParser::finalizeConverter(logchar c) {
  +  PatternConverterPtr pc;
  +
  +  LogString converterId(extractConverter(c));
  +
  +  PatternConverterFactory factory = findConverterClass(converterId);
  +
  +  std::vector<LogString> options(extractOptions());
  +
  +
  +  //System.out.println("Option is [" + option + "]");
  +  if (factory != NULL) {
  +    pc = (*factory)(formattingInfo, options);
  +    currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  +  } else {
  +    std::basic_ostringstream<logchar> os;
  +    if (converterId.empty()) {
  +        os << LOG4CXX_STR("Empty conversion specifier starting at position ");
  +    } else {
  +        os << LOG4CXX_STR("Unrecognized conversion specifier [")
  +           << converterId
  +           << LOG4CXX_STR("] starting at position ");
  +    }
  +    os << i << LOG4CXX_STR(" in conversion pattern.");
  +    logError(os.str());
  +    pc = new LiteralPatternConverter(currentLiteral);
  +    currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  +  }
  +  addConverter(pc);
   }
   
  +
  +
   void PatternParser::addConverter(PatternConverterPtr& pc)
   {
           currentLiteral.erase(currentLiteral.begin(), currentLiteral.end());
  @@ -395,39 +411,34 @@
           formattingInfo.reset();
   }
   
  -// ---------------------------------------------------------------------
  -//                      PatternConverters
  -// ---------------------------------------------------------------------
  -PatternParser::BasicPatternConverter::BasicPatternConverter(const FormattingInfo& formattingInfo, int type)
  -: PatternConverter(formattingInfo), type(type)
  -{
  +PatternParser::PatternConverterMap PatternParser::getConverterRegistry() const {
  +   return converterRegistry;
   }
   
  -void PatternParser::BasicPatternConverter::convert(LogString& sbuf,
  -        const spi::LoggingEventPtr& event,
  -        Pool& pool) const
  -{
  -        switch(type)
  -        {
  -        case RELATIVE_TIME_CONVERTER:
  -                sbuf.append(
  -                  StringHelper::toString((event->getTimeStamp() - LoggingEvent::getStartTime())/1000, pool));
  -                break;
  -        case THREAD_CONVERTER:
  -                sbuf.append(event->getThreadName());
  -                break;
  -        case LEVEL_CONVERTER:
  -                sbuf.append(event->getLevel()->toString());
  -                break;
  -        case NDC_CONVERTER:
  -                sbuf.append(event->getNDC());
  -                break;
  -        case MESSAGE_CONVERTER:
  -                sbuf.append(event->getRenderedMessage());
  -                break;
  +void PatternParser::setConverterRegistry(const PatternConverterMap& newRegistry) {
  +   converterRegistry = newRegistry;
  +}
  +
  +
  +int PatternParser::getPrecision(
  +    const std::vector<LogString>& options) {
  +    int r = 0;
  +    if (options.size() > 0 && !options[0].empty()) {
  +        r = StringHelper::toInt(options[0]);
  +        if (r < 0) {
  +          LogString msg(LOG4CXX_STR("Precision options ("));
  +          msg.append(options[0]);
  +          msg.append(LOG4CXX_STR(") isn't a positive integer."));
  +          PatternParser::logError(msg);
           }
  +    }
  +    return r;
   }
   
  +
  +// ---------------------------------------------------------------------
  +//                      PatternConverters
  +// ---------------------------------------------------------------------
   PatternParser::LiteralPatternConverter::LiteralPatternConverter(const LogString& value)
   : literal(value)
   {
  @@ -441,28 +452,70 @@
           sbuf.append(literal);
   }
   
  -PatternParser::DatePatternConverter::DatePatternConverter(const FormattingInfo& formattingInfo, DateFormat * df)
  -: PatternConverter(formattingInfo), df(df)
  +PatternParser::DatePatternConverter::DatePatternConverter(const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& options)
  +: PatternConverter(formattingInfo), df(createDateFormat(options))
   {
   }
   
  -PatternParser::DatePatternConverter::~DatePatternConverter()
  -{
  -        delete df;
  +DateFormatPtr PatternParser::DatePatternConverter::createDateFormat(
  +    const std::vector<LogString>& options) {
  +    DateFormatPtr df;
  +    if (options.size() == 0) {
  +        df = new ISO8601DateFormat();
  +    } else {
  +       LogString dateFormatStr(options[0]);
  +
  +       if(dateFormatStr.empty() ||
  +            StringHelper::equalsIgnoreCase(dateFormatStr,
  +            LOG4CXX_STR("ISO8601"), LOG4CXX_STR("iso8601"))) {
  +            df = new ISO8601DateFormat();
  +       } else if(StringHelper::equalsIgnoreCase(dateFormatStr,
  +            LOG4CXX_STR("ABSOLUTE"), LOG4CXX_STR("absolute"))) {
  +            df = new AbsoluteTimeDateFormat();
  +       } else if(StringHelper::equalsIgnoreCase(dateFormatStr,
  +            LOG4CXX_STR("DATE"), LOG4CXX_STR("date"))) {
  +            df = new DateTimeDateFormat();
  +       } else {
  +         if (dateFormatStr.find(LOG4CXX_STR('%')) == std::string::npos) {
  +            df = new SimpleDateFormat(dateFormatStr);
  +         } else {
  +            df = new StrftimeDateFormat(dateFormatStr);
  +         }
  +       }
  +       if (options.size() >= 2) {
  +         TimeZonePtr tz(TimeZone::getTimeZone(options[1]));
  +         if (tz != NULL) {
  +            df->setTimeZone(tz);
  +         }
  +       }
  +    }
  +    df = new CachedDateFormat(df);
  +    return df;
   }
   
  +
  +
   void PatternParser::DatePatternConverter::convert(LogString& sbuf,
           const spi::LoggingEventPtr& event, Pool& p) const
   {
           df->format(sbuf, event->getTimeStamp(), p);
   }
   
  -PatternParser::MDCPatternConverter::MDCPatternConverter(const FormattingInfo& formattingInfo, const LogString& key)
  -: PatternConverter(formattingInfo), key(key)
  +PatternParser::PropertiesPatternConverter::PropertiesPatternConverter(const FormattingInfo& formattingInfo,
  +   const std::vector<LogString>& options)
  +: PatternConverter(formattingInfo), key(getKey(options))
   {
   }
   
  -void PatternParser::MDCPatternConverter::convert(LogString& sbuf,
  +LogString PatternParser::PropertiesPatternConverter::getKey(const std::vector<LogString>& options) {
  +  if (options.size() > 0) {
  +    return options[0];
  +  }
  +  return LogString();
  +}
  +
  +void PatternParser::PropertiesPatternConverter::convert(LogString& sbuf,
           const spi::LoggingEventPtr& event,
           Pool& pool) const
   {
  @@ -498,38 +551,91 @@
   }
   
   
  -PatternParser::LocationPatternConverter::LocationPatternConverter(const FormattingInfo& formattingInfo, int type)
  -: PatternConverter(formattingInfo), type(type)
  +PatternParser::FullLocationPatternConverter::FullLocationPatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
   {
   }
   
  -void PatternParser::LocationPatternConverter::convert(LogString& sbuf,
  +void PatternParser::FullLocationPatternConverter::convert(LogString& sbuf,
           const spi::LoggingEventPtr& event, Pool& pool) const
   {
           const LocationInfo& locInfo = event->getLocationInformation();
  -        switch(type)
  -        {
  -        case FULL_LOCATION_CONVERTER:
  -                Transcoder::decode(locInfo.getFileName(), sbuf);
  -                sbuf.append(1, LOG4CXX_STR('('));
  -                sbuf.append(StringHelper::toString(locInfo.getLineNumber(), pool));
  -                sbuf.append(1, LOG4CXX_STR(')'));
  -                break;
  -        case LINE_LOCATION_CONVERTER:
  -                sbuf.append(StringHelper::toString(locInfo.getLineNumber(), pool));
  -                break;
  -        case FILE_LOCATION_CONVERTER:
  -                Transcoder::decode(locInfo.getFileName(), sbuf);
  -        }
  +        Transcoder::decode(locInfo.getFileName(), sbuf);
  +        sbuf.append(1, LOG4CXX_STR('('));
  +        sbuf.append(StringHelper::toString(locInfo.getLineNumber(), pool));
  +        sbuf.append(1, LOG4CXX_STR(')'));
  +}
  +
  +PatternParser::LineLocationPatternConverter::LineLocationPatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
  +}
  +
  +void PatternParser::LineLocationPatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        const LocationInfo& locInfo = event->getLocationInformation();
  +        sbuf.append(StringHelper::toString(locInfo.getLineNumber(), pool));
  +}
  +
  +PatternParser::FileLocationPatternConverter::FileLocationPatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
  +}
  +
  +void PatternParser::FileLocationPatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        const LocationInfo& locInfo = event->getLocationInformation();
  +        Transcoder::decode(locInfo.getFileName(), sbuf);
  +}
  +
  +PatternParser::MethodLocationPatternConverter::MethodLocationPatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
  +}
  +
  +void PatternParser::MethodLocationPatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        const LocationInfo& locInfo = event->getLocationInformation();
  +        Transcoder::decode(locInfo.getMethodName(), sbuf);
  +}
  +
  +PatternParser::ClassNamePatternConverter::ClassNamePatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
   }
   
  -PatternParser::CategoryPatternConverter::CategoryPatternConverter(const FormattingInfo&
  -        formattingInfo, int precision)
  -: PatternConverter(formattingInfo), precision(precision)
  +void PatternParser::ClassNamePatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        const LocationInfo& locInfo = event->getLocationInformation();
  +        Transcoder::decode(locInfo.getClassName(), sbuf);
  +}
  +
  +
  +
  +PatternParser::LoggerPatternConverter::LoggerPatternConverter(const FormattingInfo&
  +        formattingInfo, const std::vector<LogString>& options)
  +: PatternConverter(formattingInfo), precision(PatternParser::getPrecision(options))
   {
   }
   
  -void PatternParser::CategoryPatternConverter::convert(LogString& sbuf,
  +
  +
  +
  +void PatternParser::LoggerPatternConverter::convert(LogString& sbuf,
           const spi::LoggingEventPtr& event,
           Pool& pool) const
   {
  @@ -562,3 +668,95 @@
   
   
   
  +PatternParser::MessagePatternConverter::MessagePatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
  +}
  +
  +void PatternParser::MessagePatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        sbuf.append(event->getRenderedMessage());
  +}
  +
  +PatternParser::LineSeparatorPatternConverter::LineSeparatorPatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
  +}
  +
  +void PatternParser::LineSeparatorPatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        sbuf.append(LOG4CXX_EOL);
  +}
  +
  +PatternParser::RelativeTimePatternConverter::RelativeTimePatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
  +}
  +
  +void PatternParser::RelativeTimePatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        formatter.format(sbuf, event->getTimeStamp(), pool);
  +}
  +
  +PatternParser::ThreadPatternConverter::ThreadPatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
  +}
  +
  +void PatternParser::ThreadPatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        sbuf.append(event->getThreadName());
  +}
  +
  +
  +
  +PatternParser::ThrowableInformationPatternConverter::ThrowableInformationPatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
  +}
  +
  +void PatternParser::ThrowableInformationPatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        sbuf.append(LOG4CXX_STR("ThrowableInformation not implemented"));
  +}
  +
  +PatternParser::NDCPatternConverter::NDCPatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
  +}
  +
  +void PatternParser::NDCPatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        sbuf.append(event->getNDC());
  +}
  +
  +PatternParser::LevelPatternConverter::LevelPatternConverter(
  +    const FormattingInfo& formattingInfo,
  +    const std::vector<LogString>& opions)
  +: PatternConverter(formattingInfo)
  +{
  +}
  +
  +void PatternParser::LevelPatternConverter::convert(LogString& sbuf,
  +        const spi::LoggingEventPtr& event, Pool& pool) const
  +{
  +        sbuf.append(event->getLevel()->toString());
  +}
  
  
  
  1.12      +16 -7     logging-log4cxx/src/timezone.cpp
  
  Index: timezone.cpp
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/src/timezone.cpp,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- timezone.cpp	15 Feb 2005 23:56:01 -0000	1.11
  +++ timezone.cpp	18 Feb 2005 17:18:54 -0000	1.12
  @@ -1,9 +1,18 @@
  -/* * Copyright 2003,2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License");
  -* you may not use this file except in compliance with the License. * You may obtain a copy of the License at *
  -*      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software
  -* distributed under the License is distributed on an "AS IS" BASIS,
  -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  -* See the License for the specific language governing permissions and * limitations under the License. */
  +/*
  + * Copyright 2003,2005 The Apache Software Foundation.
  + *
  + * Licensed under the Apache License, Version 2.0 (the "License");
  + * you may not use this file except in compliance with the License.
  + * You may obtain a copy of the License at
  + *
  + *      http://www.apache.org/licenses/LICENSE-2.0
  + *
  + * Unless required by applicable law or agreed to in writing, software
  + * distributed under the License is distributed on an "AS IS" BASIS,
  + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  + * See the License for the specific language governing permissions and
  + * limitations under the License.
  + */
   
   #include <log4cxx/helpers/timezone.h>
   #include <stdlib.h>
  @@ -139,7 +148,7 @@
   {
     if ( id == LOG4CXX_STR("GMT") )
     {
  -    return log4cxx::helpers::TimeZoneImpl::LocalTimeZone::getInstance();
  +    return log4cxx::helpers::TimeZoneImpl::GMTTimeZone::getInstance();
     }
     if ( id.length() >= 5 && id.substr( 0, 3 ) == LOG4CXX_STR("GMT") )
     {
  
  
  
  1.3       +1 -1      logging-log4cxx/tests/input/Makefile.am
  
  Index: Makefile.am
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/tests/input/Makefile.am,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Makefile.am	10 Feb 2005 05:07:31 -0000	1.2
  +++ Makefile.am	18 Feb 2005 17:18:54 -0000	1.3
  @@ -1,2 +1,2 @@
  -SUBDIRS = ndb performance xml
  +SUBDIRS = ndc performance xml
   EXTRA_DIST = *.properties
  
  
  
  1.7       +9 -1      logging-log4cxx/tests/src/helpers/timezonetestcase.cpp
  
  Index: timezonetestcase.cpp
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/tests/src/helpers/timezonetestcase.cpp,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- timezonetestcase.cpp	15 Feb 2005 23:56:04 -0000	1.6
  +++ timezonetestcase.cpp	18 Feb 2005 17:18:54 -0000	1.7
  @@ -1,5 +1,5 @@
   /*
  - * Copyright 2004 The Apache Software Foundation.
  + * Copyright 2004,2005 The Apache Software Foundation.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
  @@ -40,6 +40,7 @@
             CPPUNIT_TEST(test3);
             CPPUNIT_TEST(test4);
             CPPUNIT_TEST(test5);
  +          CPPUNIT_TEST(test6);
     CPPUNIT_TEST_SUITE_END();
   
   #define MICROSECONDS_PER_DAY APR_INT64_C(86400000000)
  @@ -108,6 +109,13 @@
     CPPUNIT_ASSERT_EQUAL(6, exploded.tm_hour);
   }
   
  +/**
  + * Checks the GMT timezone
  + */
  +void test6() {
  +  TimeZonePtr tz(TimeZone::getTimeZone(LOG4CXX_STR("GMT")));
  +  CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("GMT"), tz->getID());
  +}
   
   
   };
  
  
  
  1.4       +15 -2     logging-log4cxx/tests/src/pattern/num343patternconverter.cpp
  
  Index: num343patternconverter.cpp
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/tests/src/pattern/num343patternconverter.cpp,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- num343patternconverter.cpp	11 Dec 2004 04:53:29 -0000	1.3
  +++ num343patternconverter.cpp	18 Feb 2005 17:18:54 -0000	1.4
  @@ -1,5 +1,5 @@
   /*
  - * Copyright 2003,2004 The Apache Software Foundation.
  + * Copyright 2003,2005 The Apache Software Foundation.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
  @@ -18,8 +18,21 @@
   
   using namespace log4cxx;
   using namespace log4cxx::helpers;
  +using namespace log4cxx::pattern;
   
  -void Num343PatternConverter::convert(LogString& sbuf, const spi::LoggingEventPtr& event)
  +Num343PatternConverter::Num343PatternConverter() {
  +}
  +
  +PatternConverter* Num343PatternConverter::newInstance(
  +   const FormattingInfo& info,
  +   const std::vector<LogString>& options) {
  +   return new Num343PatternConverter();
  +}
  +
  +
  +void Num343PatternConverter::convert(LogString& sbuf,
  +    const spi::LoggingEventPtr& event,
  +    Pool& pool) const
   {
           sbuf.append(LOG4CXX_STR("343"));
   }
  
  
  
  1.6       +17 -6     logging-log4cxx/tests/src/pattern/num343patternconverter.h
  
  Index: num343patternconverter.h
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/tests/src/pattern/num343patternconverter.h,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- num343patternconverter.h	15 Feb 2005 23:56:04 -0000	1.5
  +++ num343patternconverter.h	18 Feb 2005 17:18:54 -0000	1.6
  @@ -1,5 +1,5 @@
   /*
  - * Copyright 2003,2004 The Apache Software Foundation.
  + * Copyright 2003,2005 The Apache Software Foundation.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
  @@ -15,12 +15,23 @@
    */
   
   #include <log4cxx/helpers/patternconverter.h>
  +#include <vector>
   
   namespace log4cxx
   {
  -   class Num343PatternConverter : public helpers::PatternConverter
  -   {
  -   public:
  -      void convert(LogString& sbuf, const spi::LoggingEventPtr& event);
  -   };
  +   namespace pattern {
  +     class Num343PatternConverter : public log4cxx::helpers::PatternConverter
  +     {
  +     public:
  +       Num343PatternConverter();
  +       static log4cxx::helpers::PatternConverter* newInstance(
  +          const log4cxx::helpers::FormattingInfo& info,
  +          const std::vector<LogString>& options);
  +
  +     protected:
  +     virtual void convert(LogString& sbuf,
  +              const log4cxx::spi::LoggingEventPtr& event,
  +              log4cxx::helpers::Pool& pool) const;
  +     };
  +   }
   }
  
  
  
  1.8       +152 -2    logging-log4cxx/tests/src/pattern/patternparsertestcase.cpp
  
  Index: patternparsertestcase.cpp
  ===================================================================
  RCS file: /home/cvs/logging-log4cxx/tests/src/pattern/patternparsertestcase.cpp,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- patternparsertestcase.cpp	15 Feb 2005 23:56:04 -0000	1.7
  +++ patternparsertestcase.cpp	18 Feb 2005 17:18:54 -0000	1.8
  @@ -1,5 +1,5 @@
   /*
  - * Copyright 2003,2004 The Apache Software Foundation.
  + * Copyright 2003,2005 The Apache Software Foundation.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
  @@ -24,16 +24,29 @@
   
   #include "num343patternconverter.h"
   #include "../testchar.h"
  +#include "../insertwide.h"
   #include <log4cxx/spi/loggerrepository.h>
  -
  +#include <log4cxx/helpers/patternparser.h>
  +#include <log4cxx/helpers/patternconverter.h>
  +#include <log4cxx/helpers/relativetimedateformat.h>
  +#include <log4cxx/helpers/simpledateformat.h>
   
   using namespace log4cxx;
   using namespace log4cxx::helpers;
   using namespace log4cxx::spi;
  +using namespace log4cxx::pattern;
  +
   
   class PatternParserTestCase : public CppUnit::TestFixture
   {
      CPPUNIT_TEST_SUITE(PatternParserTestCase);
  +      CPPUNIT_TEST(testNewWord);
  +      CPPUNIT_TEST(testNewWord2);
  +      CPPUNIT_TEST(testBogusWord1);
  +      CPPUNIT_TEST(testBogusWord2);
  +      CPPUNIT_TEST(testBasic1);
  +      CPPUNIT_TEST(testBasic2);
  +      CPPUNIT_TEST(testMultiOption);
      CPPUNIT_TEST_SUITE_END();
   
      LoggerPtr logger;
  @@ -52,6 +65,143 @@
      {
         logger->getLoggerRepository()->resetConfiguration();
      }
  +
  +   void convert(LoggingEventPtr& event,
  +      PatternConverterPtr& head,
  +      Pool& p,
  +      LogString& dst) {
  +     PatternConverterPtr c(head);
  +
  +     while (c != NULL) {
  +       c->format(dst, event, p);
  +       c = c->next;
  +     }
  +   }
  +
  +
  +   void testNewWord()  {
  +     PatternParser patternParser(LOG4CXX_STR("%z343"));
  +     PatternParser::PatternConverterMap ruleRegistry;
  +     LogString name(LOG4CXX_STR("z343"));
  +     ruleRegistry.insert(
  +        PatternParser::PatternConverterMap::value_type(name,
  +           Num343PatternConverter::newInstance));
  +
  +     patternParser.setConverterRegistry(ruleRegistry);
  +
  +     PatternConverterPtr head(patternParser.parse());
  +
  +     Pool p;
  +     LogString result;
  +     convert(event, head, p, result);
  +     CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("343"), result);
  +   }
  +
  +
  +   /* Test whether words starting with the letter 'n' are treated differently,
  +    * which was previously the case by mistake.
  +    */
  +   void testNewWord2()  {
  +     PatternParser patternParser(LOG4CXX_STR("%n343"));
  +
  +     PatternParser::PatternConverterMap ruleRegistry;
  +     LogString name(LOG4CXX_STR("n343"));
  +     ruleRegistry.insert(
  +        PatternParser::PatternConverterMap::value_type(name,
  +           Num343PatternConverter::newInstance));
  +
  +     patternParser.setConverterRegistry(ruleRegistry);
  +
  +     PatternConverterPtr head(patternParser.parse());
  +
  +     Pool p;
  +     LogString result;
  +     convert(event, head, p, result);
  +     CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("343"), result);
  +   }
  +
  +   void testBogusWord1()  {
  +     PatternParser patternParser(LOG4CXX_STR("%, foobar"));
  +     PatternConverterPtr head(patternParser.parse());
  +
  +     Pool p;
  +     LogString result;
  +     convert(event, head, p, result);
  +
  +     CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("%, foobar"), result);
  +   }
  +
  +   void testBogusWord2()  {
  +     PatternParser patternParser(LOG4CXX_STR("xyz %, foobar"));
  +     PatternConverterPtr head = patternParser.parse();
  +
  +     Pool p;
  +     LogString result;
  +     convert(event, head, p, result);
  +
  +
  +     CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("xyz %, foobar"), result);
  +   }
  +
  +   void testBasic1()  {
  +     PatternParser patternParser(LOG4CXX_STR("hello %-5level - %m%n"));
  +     PatternConverterPtr head = patternParser.parse();
  +
  +     Pool p;
  +     LogString result;
  +     convert(event, head, p, result);
  +
  +     CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("hello INFO  - msg 1") LOG4CXX_EOL, result);
  +   }
  +
  +   void testBasic2()  {
  +     PatternParser patternParser(
  +       LOG4CXX_STR("%relative %-5level [%thread] %logger - %m%n"));
  +     PatternConverterPtr head = patternParser.parse();
  +
  +     Pool pool;
  +     LogString result;
  +     convert(event, head, pool, result);
  +
  +
  +     RelativeTimeDateFormat relativeFormat;
  +     LogString expected;
  +     relativeFormat.format(expected, event->getTimeStamp(), pool);
  +
  +     expected.append(LOG4CXX_STR(" INFO  ["));
  +     expected.append(event->getThreadName());
  +     expected.append(LOG4CXX_STR("] "));
  +     expected.append(logger->getName());
  +     expected.append(LOG4CXX_STR(" - msg 1") LOG4CXX_EOL);
  +
  +     CPPUNIT_ASSERT_EQUAL(expected, result);
  +   }
  +
  +   void testMultiOption()  {
  +     PatternParser patternParser
  +       (LOG4CXX_STR("%d{HH:mm:ss}{GMT} %d{HH:mm:ss} %c  - %m"));
  +     PatternConverterPtr head = patternParser.parse();
  +
  +     Pool pool;
  +     LogString result;
  +     convert(event, head, pool, result);
  +
  +     SimpleDateFormat dateFormat(LOG4CXX_STR("HH:mm:ss"));
  +     LogString localTime;
  +     dateFormat.format(localTime, event->getTimeStamp(), pool);
  +
  +     dateFormat.setTimeZone(TimeZone::getGMT());
  +     LogString utcTime;
  +     dateFormat.format(utcTime, event->getTimeStamp(), pool);
  +
  +     LogString buf(utcTime);
  +     buf.append(1, LOG4CXX_STR(' '));
  +     buf.append(localTime);
  +     buf.append(LOG4CXX_STR(" org.foobar  - msg 1"));
  +     CPPUNIT_ASSERT_EQUAL(buf, result);
  +
  +   }
  +
   };
   
   CPPUNIT_TEST_SUITE_REGISTRATION(PatternParserTestCase);