partially ported based on C interface