function XMLReader(array $t_args, array $output)
{
    $my_output = [];
    foreach ($output as $key => $out) {
        $name = $key;
        $my_output[$name] = $out;
    }
    $xpath_row = $t_args['paths']['row'];
    $xpath_columns = $t_args['paths']['columns'];
    $className = generate_name('XMLReader');
    ?>

class <?php 
    echo $className;
    ?>
 {
    std::istream& my_stream;
    pugi::xml_document doc;
    const char* xpath_row;
    std::vector<const char*> xpath_columns;
    pugi::xpath_node_set rows;
    pugi::xpath_node_set::const_iterator start;
    pugi::xpath_node_set::const_iterator end;

    <?php 
    \grokit\declareDictionaries($my_output);
    ?>

public:
    <?php 
    echo $className;
    ?>
 ( GIStreamProxy& _stream ) :
        my_stream(_stream.get_stream( ))
    {
        doc.load( my_stream );

        xpath_row = "<?php 
    echo $xpath_row;
    ?>
";

        rows = doc.select_nodes(xpath_row);

        <?php 
    $push = 'xpath_columns.push_back("';
    $close_brace = '");';
    foreach ($xpath_columns as $col) {
        ?>
                <?php 
        echo $push;
        echo $col;
        echo $close_brace;
        ?>
        <?php 
    }
    ?>

        // Capture the first and last row
        start =  rows.begin();
        end = rows.end();
    }

    bool ProduceTuple( <?php 
    echo typed_ref_args($my_output);
    ?>
 ) 
    {

        if( start == end ) {
            return false;
        }
        else
        {   
            pugi::xml_node xmlnode = start->node();

            std::vector<const char*>::const_iterator it = xpath_columns.begin();

            <?php 
    $col_num = 0;
    $node_type = 'auto ';
    $select_single_node = ' = xmlnode.select_single_node(';
    $close = ');';
    $iterator_increment = '++it;';
    foreach ($my_output as $name => $type) {
        ?>
                    <?php 
        echo $node_type;
        echo ' col_';
        echo $col_num;
        echo $select_single_node;
        ?>
*it<?php 
        echo $close;
        ?>

                    <?php 
        echo \grokit\fromStringDict($name, $type, 'col_' . $col_num . '.node().child_value()');
        ?>
;

                    <?php 
        $col_num = $col_num + 1;
        ?>
                    <?php 
        echo $iterator_increment;
        ?>
            <?php 
    }
    ?>

            ++start;

            return true;
        }
    }
};

<?php 
    $sys_headers = ['vector', 'string', 'iostream', 'fstream'];
    return ['name' => $className, 'kind' => 'GI', 'output' => $my_output, 'system_headers' => $sys_headers, 'lib_headers' => ['pugixml.hpp']];
}
Example #2
0
function CSVReader(array $t_args, array $output)
{
    $my_output = [];
    // Handle case where outputs are given as template arguments
    // and not implied.
    if (\count($output) == 0) {
        grokit_assert(array_key_exists('output', $t_args), 'Did not receive any description of my output!');
        $output_list = $t_args['output'];
        grokit_assert(is_array($output_list), 'Expected list of types for template argument "output"');
        $i = 1;
        foreach ($outputs_list as $name => $out_type) {
            grokit_assert(is_datatype($out_type) || is_identifier($out_type), 'Expected only types in the "output" list');
            if (is_identifier($out_type)) {
                $out_type = lookupType($out_type->value());
            }
            $name = 'val_' . $i;
            $my_output[$name] = $out_type;
            $i += 1;
        }
    } else {
        foreach ($output as $key => $out) {
            $name = $key;
            $my_output[$name] = $out;
        }
    }
    $debug = get_default($t_args, 'debug', 0);
    $simple = get_default($t_args, 'simple', false);
    $trimCR = get_default($t_args, 'trim.cr', false);
    // Handle separator
    $separator = ',';
    if (array_key_exists('sep', $t_args) || array_key_exists('separator', $t_args)) {
        $sep = get_first_key($t_args, ['sep', 'separator']);
        grokit_assert(is_string($sep), "Got " . gettype($sep) . " instead of string for separator.");
        if (strtolower($sep) === 'tab') {
            $sep = '\\t';
        }
        grokit_assert($sep != "\n", 'CSV column delimiter cannot be new line');
        // Scream if separator is longer than one character
        grokit_assert(\strlen($sep) == 1 || $sep == '\\t', 'Expected string of length 1 for separator, got string <' . $sep . '> instead');
        $separator = $sep;
    }
    // Handle quote character
    $quotechar = '"';
    if (array_key_exists('quote', $t_args) && !is_null($t_args['quote'])) {
        grokit_assert(!$simple, 'Quote option not available for simple CSVReader');
        $quote = $t_args['quote'];
        grokit_assert(is_string($quote), "Got " . gettype($quote) . " instead of string for quote.");
        // Scream if separator is longer than one character
        grokit_assert(\strlen($quote) == 1, 'Expected string of length 1 for quote character, got string <' . $quote . '> instead');
        $quotechar = $quote;
    }
    $quotechar = addcslashes($quotechar, '\\\'');
    // Handle escape character
    $escapeChar = '\\';
    if (array_key_exists('escape', $t_args) && !is_null($t_args['escape'])) {
        grokit_assert(!$simple, 'Escape option not available for simple CSVReader');
        $escape = $t_args['escape'];
        grokit_assert(is_string($escape), 'Got ' . gettype($escape) . ' instead of string for escape character.');
        grokit_assert(\strlen($escape) == 1, 'Expected string of length 1 for escape character, got string <' . $escape . '> instead');
        $escapeChar = $escape;
    }
    $escapeChar = addcslashes($escapeChar, '\\\'');
    // Handle header lines
    $headerLines = 0;
    if (array_key_exists('skip', $t_args)) {
        $headerLines = $t_args['skip'];
        grokit_assert(is_int($headerLines), 'Got ' . gettype($headerLines) . ' instead of int for number of lines to skip.');
        grokit_assert($headerLines >= 0, 'Cannot skip a negative number of lines.');
    }
    // Maximum number of lines to read
    $maxLines = get_default($t_args, 'n', -1);
    grokit_assert(is_int($maxLines), 'Got ' . gettype($maxLines) . ' instead of int for template argument "n"');
    $nullArg = get_first_key_default($t_args, ['nullable'], false);
    $nullable = [];
    $nullStr = [];
    foreach ($my_output as $name => $type) {
        $nullable[$name] = false;
    }
    if ($nullArg === true) {
        foreach ($my_output as $name => $type) {
            $nullable[$name] = true;
            $nullStr[$name] = 'NULL';
        }
    } else {
        if (is_array($nullArg)) {
            foreach ($nullArg as $n => $v) {
                // If nullable value is an associative mapping, the value is either true/false
                // or the value of the null string
                if (is_string($n)) {
                    grokit_assert(is_string($v) || is_bool($v), 'CSVReader: nullable associative mapping must have string or boolean values');
                    grokit_assert(array_key_exists($n, $nullable), 'CSVReader: cannot make unknown attribute ' . $n . ' nullable');
                    if (is_bool($v)) {
                        $nullable[$n] = $v;
                        $nullStr[$n] = 'NULL';
                    } else {
                        $nullable[$n] = true;
                        $nullStr[$n] = $v;
                    }
                } else {
                    if (is_array($v)) {
                        grokit_assert(array_key_exists('attr', $v), 'CSVReader: Name of nullable attribute not specified');
                        $attrName = $v['attr']->name();
                        $nullable[$attrName] = true;
                        $nullStr[$attrName] = array_key_exists('null', $v) ? $v['null'] : 'NULL';
                    } else {
                        // Otherwise, it's just nullable
                        $attrName = $v->name();
                        grokit_assert(array_key_exists($attrName, $nullable), 'CSVReader: cannot make unknown attribute ' . $v . ' nullable');
                        $nullable[$attrName] = true;
                        $nullStr[$attrName] = 'NULL';
                    }
                }
            }
        } else {
            if ($nullArg === false) {
                // Nothing
            } else {
                if (is_string($nullArg)) {
                    foreach ($my_output as $name => $type) {
                        $nullable[$name] = true;
                        $nullStr[$name] = $nullArg;
                    }
                } else {
                    grokit_error('Template argument "nullable" must be boolean or array, ' . typeof($nullArg) . ' given');
                }
            }
        }
    }
    // Come up with a name for ourselves
    $className = generate_name('CSVReader');
    if ($debug >= 2) {
        foreach ($my_output as $name => $type) {
            fwrite(STDERR, "CSVReader: {$name} is nullable: " . ($nullable[$name] ? 'true' : 'false') . PHP_EOL);
        }
    }
    ?>

class <?php 
    echo $className;
    ?>
 {
    std::istream& my_stream;
    std::string fileName;

    // Template parameters
    static constexpr size_t MAX_LINES = <?php 
    echo $maxLines;
    ?>
;
    static constexpr size_t HEADER_LINES = <?php 
    echo $headerLines;
    ?>
;
    static constexpr char DELIMITER = '<?php 
    echo $separator;
    ?>
';
<?php 
    if (!$simple) {
        ?>
    static constexpr char QUOTE_CHAR = '<?php 
        echo $quotechar;
        ?>
';
    static constexpr char ESCAPE_CHAR = '<?php 
        echo $escapeChar;
        ?>
';

    typedef boost::escaped_list_separator<char> separator;
    typedef boost::tokenizer< separator > Tokenizer;
    separator my_separator;
    Tokenizer my_tokenizer;
<?php 
    }
    ?>

    // Prevent having to allocate this every time.
    std::string line;
    std::vector<std::string> tokens;

    size_t count;

<?php 
    \grokit\declareDictionaries($my_output);
    ?>

public:

    <?php 
    echo $className;
    ?>
 ( GIStreamProxy& _stream ) :
        my_stream(_stream.get_stream())
        , fileName(_stream.get_file_name())
<?php 
    if (!$simple) {
        ?>
        , my_separator(ESCAPE_CHAR, DELIMITER, QUOTE_CHAR)
        , my_tokenizer(std::string(""))
<?php 
    }
    ?>
        , count(0)
    {
<?php 
    if ($headerLines > 0) {
        ?>
        for( size_t i = 0; i < HEADER_LINES; ++i ) {
            FATALIF( !getline( my_stream, line ), "CSV Reader reached end of file before finishing header.\n" );
        }
<?php 
    }
    // If headerLines > 0
    ?>
    }

// >

    bool ProduceTuple( <?php 
    echo typed_ref_args($my_output);
    ?>
 ) {
        if (count < MAX_LINES) { //>
            count++;
        } else {
            return false;
        }

        if( getline( my_stream, line ) ) {
<?php 
    if ($trimCR) {
        ?>
            if( line.back() == '\r' ) {
                line.pop_back();
            }
<?php 
    }
    // if trimCR
    if (!$simple) {
        if ($debug >= 1) {
            ?>
            try {
<?php 
        }
        // if debug >= 1
        ?>
            my_tokenizer.assign( line, my_separator );
<?php 
        if ($debug >= 1) {
            ?>
            } catch(...) {
                FATAL("CSVReader for file %s failed on line: %s", fileName.c_str(), line.c_str());
            }
<?php 
        }
        // if debug >= 1
        ?>
            Tokenizer::iterator it = my_tokenizer.begin();

<?php 
        foreach ($my_output as $name => $type) {
            if ($nullable[$name]) {
                // nullable
                ?>
            <?php 
                \grokit\fromStringNullable($name, $type, 'it->c_str()', true, $nullStr[$name]);
                ?>

<?php 
            } else {
                // not nullable
                ?>
            <?php 
                echo \grokit\fromStringDict($name, $type, 'it->c_str()');
                ?>
;
<?php 
            }
            // end nullable check
            ?>
            ++it;
<?php 
        }
        // foreach output
    } else {
        ?>
            for( char & c : line ) {
                if( c == DELIMITER )
                    c = '\0';
            }

            const char * ptr = line.c_str();
<?php 
        $first = true;
        foreach ($my_output as $name => $type) {
            if ($first) {
                $first = false;
            } else {
                ?>
            while( *(ptr++) != '\0' )
                ; // Advance past next delimiter
<?php 
            }
            // not first output
            if ($nullable[$name]) {
                ?>
            <?php 
                echo \grokit\fromStringNullable($name, $type, 'ptr', true, $nullStr[$name]);
            } else {
                // not nullable
                ?>
            <?php 
                echo \grokit\fromStringDict($name, $type, 'ptr');
                ?>
;
<?php 
            }
            // if nullable
        }
        // foreach output
    }
    // if simple reader
    ?>

            return true;
        }
        else {
            return false;
        }
    }

<?php 
    \grokit\declareDictionaryGetters($my_output);
    ?>
};

<?php 
    $sys_headers = ['vector', 'string', 'iostream', 'cstdint'];
    if (!$simple) {
        $sys_headers[] = 'boost/tokenizer.hpp';
    }
    return ['name' => $className, 'kind' => 'GI', 'output' => $my_output, 'system_headers' => $sys_headers, 'user_headers' => ['GIStreamInfo.h', 'Dictionary.h', 'DictionaryManager.h']];
}