|
Boost Users : |
Subject: Re: [Boost-users] [Preprocessor] MSVC nonstandard macro expansion workaround?
From: Roger Leigh (rleigh_at_[hidden])
Date: 2016-03-04 05:33:33
On 03/03/2016 19:37, paul Fultz wrote:
>> On Thursday, March 3, 2016 7:50 AM, "rleigh_at_[hidden]" <rleigh_at_[hidden]> wrote:
>> I've been trying to get Boost.Preprocessor to run a nested for loop over
>> two sequences to output nested switch blocks and case statements. This
>> works fine with GCC and clang. Unfortunately it's broken with MSVC. If
>> anyone had any thoughts on what I might need to tweak to enable the code
>> to work with MSVC, I'd be very appreciative. Even if it's as nasty as a
>>
>
>> big ifdef with an alternative set of macros!
>
>
> I don't have MSVC available to test this right now, but you could try adding an extra scan and avoid using strange operator combinations as well:
>
> BOOST_PP_EXPAND(BOOST_PP_EXPAND(BOOST_PP_SEQ_FOR_EACH(LT_TOPLEVEL,, LASERTYPE_VALUES)));
>
> If that doesn't work. Would you be able to post the PP output of what gets expanded inside of main? This would help diagnose the issue, until someone can look at it with MSVC.
With the plain source as I posted: failure to expand a whole set of macros.
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_VARIADIC_ELEM_3'
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_BOOL'
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_BOOL_I'
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_VARIADIC_ELEM_2'
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_DEC'
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_DEC_I'
--------
enum LaserType
{
EXCIMER, GAS, METALVAPOR, SOLIDSTATE, DYE, SEMICONDUCTOR,
FREEELECTRON, OTHER
};
int main() {
std::cout << "Test toplevel: " << LaserType(EXCIMER ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(3, (LT_NESTED, EXCIMER,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_3, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, EXCIMER,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(GAS ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(4, (LT_NESTED, GAS,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_4, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, GAS,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(METALVAPOR ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(5, (LT_NESTED, METALVAPOR,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_5, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, METALVAPOR,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(SOLIDSTATE ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(6, (LT_NESTED, SOLIDSTATE,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_6, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, SOLIDSTATE,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout
<< "Test toplevel: " << LaserType(DYE ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(7, (LT_NESTED, DYE,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_7, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, DYE,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(SEMICONDUCTOR ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(8, (LT_NESTED, SEMICONDUCTOR,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_8, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, SEMICONDUCTOR,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(FREEELECTRON ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(9, (LT_NESTED, FREEELECTRON,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_9, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, FREEELECTRON,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(OTHER ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(10, (LT_NESTED, OTHER,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_10, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, OTHER,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); ;
}
--------
With the addition of another BOOST_PP_EXPAND at the top level, I get the
same except for minor whitespace differences:
test-pp.cpp(22) : warning C4003: not enough actual parameters for
macro 'BOOST_PP_VARIADIC_ELEM_3'
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_BOOL'
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_BOOL_I'
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_VARIADIC_ELEM_2'
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_DEC'
test-pp.cpp(22) : warning C4003: not enough actual parameters for macro
'BOOST_PP_DEC_I'
--------
enum LaserType
{
EXCIMER, GAS, METALVAPOR, SOLIDSTATE, DYE, SEMICONDUCTOR,
FREEELECTRON, OTHER
};
int main() {
std::cout << "Test toplevel: " << LaserType(EXCIMER ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(3, (LT_NESTED, EXCIMER,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_3, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, EXCIMER,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(GAS ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(4, (LT_NESTED, GAS,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_4, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, GAS,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(METALVAPOR ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(5, (LT_NESTED, METALVAPOR,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_5, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, METALVAPOR,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(SOLIDSTATE ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(6, (LT_NESTED, SOLIDSTATE,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_6, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, SOLIDSTATE,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout
<< "Test toplevel: " << LaserType(DYE ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(7, (LT_NESTED, DYE,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_7, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, DYE,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(SEMICONDUCTOR ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(8, (LT_NESTED, SEMICONDUCTOR,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_8, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, SEMICONDUCTOR,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(FREEELECTRON ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(9, (LT_NESTED, FREEELECTRON,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_9, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, FREEELECTRON,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O,
BOOST_PP_SEQ_FOR_EACH_M); std::cout << "Test toplevel: " <<
LaserType(OTHER ) << " \n";
BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_SEQ_FOR_EACH_M,
BOOST_PP_TUPLE_EAT_2)(10, (LT_NESTED, OTHER,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8)) BOOST_PP_IIF_BOOST_PP_BOOL_(BOOST_PP_FOR_10, BOOST_PP_TUPLE_EAT_4)((
BOOST_PP_EXPAND(LT_NESTED, OTHER,
(EXCIMER)(GAS)(METALVAPOR)(SOLIDSTATE)(DYE)(SEMICONDUCTOR)(FREEELECTRON)(OTHER),
8), ,
BOOST_PP_IIF_BOOST_PP_BOOL_BOOST_PP_DEC_(BOOST_PP_SEQ_FOR_EACH_O_I_TAIL,
BOOST_PP_SEQ_FOR_EACH_O_I_NIL) (), BOOST_PP_DEC_ ),
BOOST_PP_SEQ_FOR_EACH_P, BOOST_PP_SEQ_FOR_EACH_O, BOOST_PP_SEQ_FOR_EACH_M);;
}
--------
I've tried changing the expansion in the LT_TOPLEVEL macro with variants
of PP_DEFER/PP_SEQ_FOR_EACH_R/PP_EXPAND without it making any
significant difference. Oh MSVC how I detest thee!
Regards,
Roger
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net