#!/usr/bin/env python

# Copyright (c) 2005-2009 <NAME>
#
# Distributed under the MIT license (See accompanying file
# LICENSE.txt or copy at http://jagpdf.org/LICENSE.txt)
#

import StringIO
import time
import os
import string
import re
import sys


##
## Globals
##
g_curr_time = time.strftime( '%c' )

##
## Templates
##
prologue = """// Copyright (c) 2005-2009 <NAME>
//
// Distributed under the MIT license (See accompanying file
// LICENSE.txt or copy at http://jagpdf.org/LICENSE.txt)
//

// this file was generated by msggen.py
"""

epilogue = """
} // namespace jag
/** EOF @file */
"""

msg_header_file="""
#include <core/errlib/except.h>
#include <boost/format/format_fwd.hpp>
#include <boost/shared_ptr.hpp>

namespace jag
{

${header_cont}
"""

msg_impl_file="""
#include <${msg_include}>
#include <boost/format.hpp>

using namespace boost;

namespace jag
{

static
shared_ptr<format> my_fmt( const char* fmtstr )
{
    shared_ptr<format> fmter( new format(fmtstr) );
    fmter->exceptions(io::no_error_bits);
    return fmter;
}

${impl_cont}
"""

msg_decl="""
struct msg_${msg_name}
{
    boost::shared_ptr<boost::format> m_fmt;
public:
    msg_${msg_name}( ${ctor_args} );
    operator msg_info_t() const;
    static unsigned msg_id();
};

"""

msg_def="""
msg_${msg_name}::msg_${msg_name}( ${ctor_args} )
{
    m_fmt = my_fmt( \"${msg_txt}\" );
    *m_fmt ${fmt_action};
}

msg_${msg_name}::operator msg_info_t() const
{
    return msg_info_t( msg_id(), m_fmt->str() );
}

unsigned msg_${msg_name}::msg_id()
{
    return ${msg_id};
}


"""

try:
    import hashlib
    md5_creator = hashlib.md5
except ImportError:
    import md5
    md5_creator = md5.new

def get_guards( fname ):
    if os.path.splitext(fname)[1]!='.h':
        return '',''
    m = md5_creator()
    m.update(os.path.basename(fname))
    guard = 'JAG_' + m.hexdigest()
    return string.Template( '#ifndef ${guard}\n#define ${guard}\n' ).substitute( locals()),\
           string.Template( '#endif // ${guard}\n' ).substitute( locals())



re_fmt_plh = re.compile( "%([0-9])(.)%" )
def handler_msg( opts, line ):
#    print 'msg:', line
    msg_id, msg_name, msg_txt = line.split( None, 2 )
    # form message id
    msg_id = int(msg_id)
    assert msg_id < 65536      # msg id is 16bit
    msg_id += opts['module_id']
    msg_id = "0x%x" % msg_id
    if msg_id in opts.setdefault( 'msgids', set() ):
        assert not "duplicate ids"
    opts['msgids'].add( msg_id )
    # form formatting args
    fmtargs_s = set()
    for item in re_fmt_plh.findall( msg_txt ):
        fmtargs_s.add( item )
    fmtargs_l = [ (int(n), f) for n,f in fmtargs_s ]
    fmtargs_l.sort()
    ctor_args, fmt_action = [], ''
    arg2type = { 'i' : 'int',\
                 's' : 'char const*' }
    for i, (n,f) in enumerate( fmtargs_l ):
        assert i+1 == n   # check missing fmt arguments (one-based)
        ctor_args.append( "%s p%d" % (arg2type[f], n ) )
        fmt_action = fmt_action + " %% p%d" % n
    ctor_args = ", ".join( ctor_args )
    # remove type specifier from the fmt str
    msg_txt = re_fmt_plh.sub( lambda m: '%%%d%%' % int(m.group(0)[1]), msg_txt )
    # write message declaration and definition
    opts['msg_h'].write( string.Template( msg_decl ).substitute( locals() ) )
    opts['msg_c'].write( string.Template( msg_def ).substitute( locals() ) )



def finalize( fname, buff ):
    fout = open( fname, 'wb' )
    guard_start, guard_end = get_guards( fname )
    if fname.endswith( 'cpp' ):
        fout.write( '#include "precompiled.h"\n' )
    fout.write( prologue )
    fout.write( guard_start )
    fout.write( buff )
    fout.write( epilogue )
    fout.write( guard_end )
    fout.close()



remsg_head = re.compile( '\[messages=([0-9]+)\]' )
def main( infile, impl_fname, header_fname ):
    opts = dict( msg_h = StringIO.StringIO(),\
                 msg_c = StringIO.StringIO() )
    handler = None
    for line in open( infile ):
        line = line.strip()
        if not line or line[0] == '#':
            continue
        else:
            m = remsg_head.match( line )
            if m:
                opts['module_id']=int(m.group(1))
                assert opts['module_id'] < 256                 # module id is 8 bit
                opts['module_id'] = opts['module_id'] << 16
                handler=handler_msg
                continue

            assert handler
            handler( opts, line )

    msg_include = os.path.basename( header_fname )

    header_cont = opts['msg_h'].getvalue()
    finalize( header_fname, string.Template( msg_header_file ).substitute( locals() ) )

    impl_cont = opts['msg_c'].getvalue()
    finalize( impl_fname, string.Template( msg_impl_file ).substitute( locals() ) )


if __name__ == "__main__":
#     main( "msgdef.jmsg", "msg.cxx", "msg.h" )
#     sys.exit(0)

    if len(sys.argv) != 4:
        print "usage msggen <msgdef_file> <impl_file> <header_file>"
        sys.exit(1)

    main( sys.argv[1], sys.argv[2], sys.argv[3] )

#!/usr/bin/env python

# Copyright (c) 2005-2009 <NAME>
#
# Distributed under the MIT license (See accompanying file
# LICENSE.txt or copy at http://jagpdf.org/LICENSE.txt)
#

import StringIO
import time
import os
import string
import re
import sys


##
## Globals
##
g_curr_time = time.strftime( '%c' )

##
## Templates
##
prologue = """// Copyright (c) 2005-2009 <NAME>
//
// Distributed under the MIT license (See accompanying file
// LICENSE.txt or copy at http://jagpdf.org/LICENSE.txt)
//

// this file was generated by msggen.py
"""

epilogue = """
} // namespace jag
/** EOF @file */
"""

msg_header_file="""
#include <core/errlib/except.h>
#include <boost/format/format_fwd.hpp>
#include <boost/shared_ptr.hpp>

namespace jag
{

${header_cont}
"""

msg_impl_file="""
#include <${msg_include}>
#include <boost/format.hpp>

using namespace boost;

namespace jag
{

static
shared_ptr<format> my_fmt( const char* fmtstr )
{
    shared_ptr<format> fmter( new format(fmtstr) );
    fmter->exceptions(io::no_error_bits);
    return fmter;
}

${impl_cont}
"""

msg_decl="""
struct msg_${msg_name}
{
    boost::shared_ptr<boost::format> m_fmt;
public:
    msg_${msg_name}( ${ctor_args} );
    operator msg_info_t() const;
    static unsigned msg_id();
};

"""

msg_def="""
msg_${msg_name}::msg_${msg_name}( ${ctor_args} )
{
    m_fmt = my_fmt( \"${msg_txt}\" );
    *m_fmt ${fmt_action};
}

msg_${msg_name}::operator msg_info_t() const
{
    return msg_info_t( msg_id(), m_fmt->str() );
}

unsigned msg_${msg_name}::msg_id()
{
    return ${msg_id};
}


"""

try:
    import hashlib
    md5_creator = hashlib.md5
except ImportError:
    import md5
    md5_creator = md5.new

def get_guards( fname ):
    if os.path.splitext(fname)[1]!='.h':
        return '',''
    m = md5_creator()
    m.update(os.path.basename(fname))
    guard = 'JAG_' + m.hexdigest()
    return string.Template( '#ifndef ${guard}\n#define ${guard}\n' ).substitute( locals()),\
           string.Template( '#endif // ${guard}\n' ).substitute( locals())



re_fmt_plh = re.compile( "%([0-9])(.)%" )
def handler_msg( opts, line ):
#    print 'msg:', line
    msg_id, msg_name, msg_txt = line.split( None, 2 )
    # form message id
    msg_id = int(msg_id)
    assert msg_id < 65536      # msg id is 16bit
    msg_id += opts['module_id']
    msg_id = "0x%x" % msg_id
    if msg_id in opts.setdefault( 'msgids', set() ):
        assert not "duplicate ids"
    opts['msgids'].add( msg_id )
    # form formatting args
    fmtargs_s = set()
    for item in re_fmt_plh.findall( msg_txt ):
        fmtargs_s.add( item )
    fmtargs_l = [ (int(n), f) for n,f in fmtargs_s ]
    fmtargs_l.sort()
    ctor_args, fmt_action = [], ''
    arg2type = { 'i' : 'int',\
                 's' : 'char const*' }
    for i, (n,f) in enumerate( fmtargs_l ):
        assert i+1 == n   # check missing fmt arguments (one-based)
        ctor_args.append( "%s p%d" % (arg2type[f], n ) )
        fmt_action = fmt_action + " %% p%d" % n
    ctor_args = ", ".join( ctor_args )
    # remove type specifier from the fmt str
    msg_txt = re_fmt_plh.sub( lambda m: '%%%d%%' % int(m.group(0)[1]), msg_txt )
    # write message declaration and definition
    opts['msg_h'].write( string.Template( msg_decl ).substitute( locals() ) )
    opts['msg_c'].write( string.Template( msg_def ).substitute( locals() ) )



def finalize( fname, buff ):
    fout = open( fname, 'wb' )
    guard_start, guard_end = get_guards( fname )
    if fname.endswith( 'cpp' ):
        fout.write( '#include "precompiled.h"\n' )
    fout.write( prologue )
    fout.write( guard_start )
    fout.write( buff )
    fout.write( epilogue )
    fout.write( guard_end )
    fout.close()



remsg_head = re.compile( '\[messages=([0-9]+)\]' )
def main( infile, impl_fname, header_fname ):
    opts = dict( msg_h = StringIO.StringIO(),\
                 msg_c = StringIO.StringIO() )
    handler = None
    for line in open( infile ):
        line = line.strip()
        if not line or line[0] == '#':
            continue
        else:
            m = remsg_head.match( line )
            if m:
                opts['module_id']=int(m.group(1))
                assert opts['module_id'] < 256                 # module id is 8 bit
                opts['module_id'] = opts['module_id'] << 16
                handler=handler_msg
                continue

            assert handler
            handler( opts, line )

    msg_include = os.path.basename( header_fname )

    header_cont = opts['msg_h'].getvalue()
    finalize( header_fname, string.Template( msg_header_file ).substitute( locals() ) )

    impl_cont = opts['msg_c'].getvalue()
    finalize( impl_fname, string.Template( msg_impl_file ).substitute( locals() ) )


if __name__ == "__main__":
#     main( "msgdef.jmsg", "msg.cxx", "msg.h" )
#     sys.exit(0)

    if len(sys.argv) != 4:
        print "usage msggen <msgdef_file> <impl_file> <header_file>"
        sys.exit(1)

    main( sys.argv[1], sys.argv[2], sys.argv[3] )

#!/usr/bin/env python # Copyright (c) 2005-2009 <NAME> # # Distributed under the MIT license (See accompanying file # LICENSE.txt or copy at http://jagpdf.org/LICENSE.txt) # ## ## Globals ## ## ## Templates ## // Copyright (c) 2005-2009 <NAME> // // Distributed under the MIT license (See accompanying file // LICENSE.txt or copy at http://jagpdf.org/LICENSE.txt) //  // this file was generated by msggen.py } // namespace jag /** EOF @file */ #include <core/errlib/except.h> #include <boost/format/format_fwd.hpp> #include <boost/shared_ptr.hpp>  namespace jag {  ${header_cont} #include <${msg_include}> #include <boost/format.hpp>  using namespace boost;  namespace jag {  static shared_ptr<format> my_fmt( const char* fmtstr ) {     shared_ptr<format> fmter( new format(fmtstr) );     fmter->exceptions(io::no_error_bits);     return fmter; }  ${impl_cont} struct msg_${msg_name} {     boost::shared_ptr<boost::format> m_fmt; public:     msg_${msg_name}( ${ctor_args} );     operator msg_info_t() const;     static unsigned msg_id(); }; msg_${msg_name}::msg_${msg_name}( ${ctor_args} ) {     m_fmt = my_fmt( \"${msg_txt}\" );     *m_fmt ${fmt_action}; }  msg_${msg_name}::operator msg_info_t() const {     return msg_info_t( msg_id(), m_fmt->str() ); }  unsigned msg_${msg_name}::msg_id() {     return ${msg_id}; } #define ${guard}\n' ).substitute( locals()),\ #    print 'msg:', line # form message id # msg id is 16bit # form formatting args # check missing fmt arguments (one-based) # remove type specifier from the fmt str # write message declaration and definition # module id is 8 bit #     main( "msgdef.jmsg", "msg.cxx", "msg.h" ) #     sys.exit(0)