|
| 1 | +#WORKUNIT('name', 'C++ Record Reader Generator'); |
| 2 | + |
| 3 | +//----------------------------------------------------------------------------- |
| 4 | + |
| 5 | +GenerateDatasetReader(inFileRec, |
| 6 | + eclWatchOutput = FALSE, |
| 7 | + functionNameStr = '\'ReadDataset\'', |
| 8 | + dsParameterNameStr = '\'inFile\'', |
| 9 | + cppRowVarNameStr = '\'inRow\'', |
| 10 | + embedOptionsStr = '\'\'') := FUNCTIONMACRO |
| 11 | + IMPORT Std; |
| 12 | + LOADXML('<xml/>'); |
| 13 | + #EXPORTXML(inFileFields, inFileRec); |
| 14 | + |
| 15 | + #UNIQUENAME(inputECLRecName); |
| 16 | + #SET(inputECLRecName, #TEXT(inFileRec)); |
| 17 | + |
| 18 | + #UNIQUENAME(TextLayout); |
| 19 | + LOCAL %TextLayout% := {STRING text}; |
| 20 | + |
| 21 | + #UNIQUENAME(recLevel); |
| 22 | + #SET(recLevel, 0); |
| 23 | + |
| 24 | + #UNIQUENAME(headerNeedsStdString); |
| 25 | + #SET(headerNeedsStdString, 0); |
| 26 | + #UNIQUENAME(headerNeedsUTF); |
| 27 | + #SET(headerNeedsUTF, 0); |
| 28 | + |
| 29 | + // Create the struct that will hold each input record's data |
| 30 | + #UNIQUENAME(inputStructDef); |
| 31 | + LOCAL %inputStructDef% := DATASET |
| 32 | + ( |
| 33 | + [ |
| 34 | + ' typedef struct ' + %'inputECLRecName'% |
| 35 | + , ' {' |
| 36 | + #FOR(inFileFields) |
| 37 | + #FOR(Field) |
| 38 | + #IF(%recLevel% = 0) |
| 39 | + #IF(REGEXFIND('(string)|(data)', %'@type'%)) |
| 40 | + , ' std::string ' + %'@name'% + '; // ' + %'@ecltype'% |
| 41 | + #SET(headerNeedsStdString, 1) |
| 42 | + #ELSEIF(REGEXFIND('utf', %'@type'%)) |
| 43 | + , ' icu::UnicodeString ' + %'@name'% + '; // ' + %'@ecltype'% |
| 44 | + #SET(headerNeedsUTF, 1) |
| 45 | + #ELSEIF(%'@type'% IN ['decimal', 'udecimal']) |
| 46 | + , ' double ' + %'@name'% + '; // ' + %'@ecltype'% |
| 47 | + #ELSEIF(REGEXFIND('real', %'@type'%)) |
| 48 | + #IF(%@size% = 4) |
| 49 | + , ' float ' + %'@name'% + '; // ' + %'@ecltype'% |
| 50 | + #ELSEIF(%@size% = 8) |
| 51 | + , ' double ' + %'@name'% + '; // ' + %'@ecltype'% |
| 52 | + #ELSE |
| 53 | + #ERROR(%'@name'% + ': Unknown type ' + %'@ecltype'%) |
| 54 | + #END |
| 55 | + #ELSEIF(REGEXFIND('unsigned', %'@type'%)) |
| 56 | + #IF(%@size% = 1) |
| 57 | + , ' unsigned char ' + %'@name'% + '; // ' + %'@ecltype'% |
| 58 | + #ELSEIF(%@size% = 2) |
| 59 | + , ' uint16_t ' + %'@name'% + '; // ' + %'@ecltype'% |
| 60 | + #ELSEIF(%@size% IN [3, 4]) |
| 61 | + , ' uint32_t ' + %'@name'% + '; // ' + %'@ecltype'% |
| 62 | + #ELSEIF(%@size% IN [5, 6, 7, 8]) |
| 63 | + , ' unsigned __int64 ' + %'@name'% + '; // ' + %'@ecltype'% |
| 64 | + #END |
| 65 | + #ELSEIF(REGEXFIND('integer', %'@type'%)) |
| 66 | + #IF(%@size% = 1) |
| 67 | + , ' signed char ' + %'@name'% + '; // ' + %'@ecltype'% |
| 68 | + #ELSEIF(%@size% = 2) |
| 69 | + , ' int16_t ' + %'@name'% + '; // ' + %'@ecltype'% |
| 70 | + #ELSEIF(%@size% IN [3, 4]) |
| 71 | + , ' int32_t ' + %'@name'% + '; // ' + %'@ecltype'% |
| 72 | + #ELSEIF(%@size% IN [5, 6, 7, 8]) |
| 73 | + , ' signed __int64 ' + %'@name'% + '; // ' + %'@ecltype'% |
| 74 | + #END |
| 75 | + #ELSEIF(%'@type'% = 'boolean') |
| 76 | + , ' bool ' + %'@name'% + '; // ' + %'@ecltype'% |
| 77 | + #ELSE |
| 78 | + #ERROR(%'@name'% + ': Unknown type ' + %'@ecltype'%) |
| 79 | + #END |
| 80 | + #END |
| 81 | + #IF(%{@isRecord}% = 1 OR %{@isDataset}% = 1) |
| 82 | + // #SET(recLevel, %recLevel% + 1) |
| 83 | + #ERROR('Child datasets or records are not supported') |
| 84 | + #ELSEIF(%{@isEnd}% = 1) |
| 85 | + // #SET(recLevel, %recLevel% - 1) |
| 86 | + #ERROR('Child datasets or records are not supported') |
| 87 | + #END |
| 88 | + #END |
| 89 | + #END |
| 90 | + , ' } ' + %'inputECLRecName'% + ';' |
| 91 | + ], |
| 92 | + %TextLayout% |
| 93 | + ); |
| 94 | + |
| 95 | + #UNIQUENAME(rowExtractionFunction, 'ReadRow_$'); |
| 96 | + #UNIQUENAME(rowExtractionCode); |
| 97 | + LOCAL %rowExtractionCode% := DATASET |
| 98 | + ( |
| 99 | + [ |
| 100 | + '' |
| 101 | + , ' void ' + %'rowExtractionFunction'% + '(const byte* row, ' + %'inputECLRecName'% + '& rowStruct)' |
| 102 | + , ' {' |
| 103 | + #FOR(inFileFields) |
| 104 | + #FOR(Field) |
| 105 | + // No need to check for reclevel because embedded structures should have |
| 106 | + // caused an error when constructing %inputStructDef% |
| 107 | + |
| 108 | + #UNIQUENAME(lvalue) |
| 109 | + #SET(lvalue, 'rowStruct.' + %'@name'%) |
| 110 | + , ' // ' + %'inputECLRecName'% + '.' + %'@name'% |
| 111 | + |
| 112 | + #IF(%'@type'% = 'varstring') |
| 113 | + #UNIQUENAME(byteCountVar) |
| 114 | + #SET(byteCountVar, %'@name'% + 'ByteCount') |
| 115 | + , ' const size32_t ' + %'byteCountVar'% + ' = strlen(reinterpret_cast<const char*>(row));' |
| 116 | + , ' ' + %'lvalue'% + ' = std::string(reinterpret_cast<const char*>(row), ' + %'byteCountVar'% + ');' |
| 117 | + , ' row += ' + %'byteCountVar'% + ';' |
| 118 | + #ELSEIF(REGEXFIND('(string)|(data)', %'@type'%)) |
| 119 | + #IF(%@size% < 0) |
| 120 | + #UNIQUENAME(byteCountVar) |
| 121 | + #SET(byteCountVar, %'@name'% + 'ByteCount') |
| 122 | + , ' const size32_t ' + %'byteCountVar'% + ' = *(reinterpret_cast<const size32_t*>(row));' |
| 123 | + , ' row += sizeof(' + %'byteCountVar'% + ');' |
| 124 | + , ' ' + %'lvalue'% + ' = std::string(reinterpret_cast<const char*>(row), ' + %'byteCountVar'% + ');' |
| 125 | + , ' row += ' + %'byteCountVar'% + ';' |
| 126 | + #ELSE |
| 127 | + , ' ' + %'lvalue'% + ' = std::string(reinterpret_cast<const char*>(row), ' + %'@size'% + ');' |
| 128 | + , ' row += ' + %'@size'% + ';' |
| 129 | + #END |
| 130 | + #ELSEIF(REGEXFIND('utf', %'@type'%)) |
| 131 | + #UNIQUENAME(charCountVar) |
| 132 | + #SET(charCountVar, %'@name'% + 'CharCount') |
| 133 | + , ' const size32_t ' + %'charCountVar'% + ' = *(reinterpret_cast<const size32_t*>(row));' |
| 134 | + , ' row += sizeof(' + %'charCountVar'% + ');' |
| 135 | + #UNIQUENAME(byteCountVar) |
| 136 | + #SET(byteCountVar, %'@name'% + 'ByteCount') |
| 137 | + , ' size32_t ' + %'byteCountVar'% + ' = rtlUtf8Size(' + %'charCountVar'% + ', reinterpret_cast<const char*>(row));' |
| 138 | + , ' ' + %'lvalue'% + ' = icu::UnicodeString(reinterpret_cast<const char*>(row), ' + %'byteCountVar'% + ', "UTF-8");' |
| 139 | + , ' row += ' + %'byteCountVar'% + ';' |
| 140 | + #ELSEIF(%'@type'% IN ['decimal', 'udecimal']) |
| 141 | + #UNIQUENAME(pushFunction) |
| 142 | + #IF(%'@type'% = 'decimal') |
| 143 | + #SET(pushFunction, 'DecPushDecimal') |
| 144 | + #ELSE |
| 145 | + #SET(pushFunction, 'DecPushUDecimal') |
| 146 | + #END |
| 147 | + #UNIQUENAME(byteCountVar) |
| 148 | + #SET(byteCountVar, %'@name'% + 'ByteCount') |
| 149 | + #UNIQUENAME(fieldPrecision) |
| 150 | + #SET(fieldPrecision, REGEXFIND('_(\\d+)$', %'@ecltype'%, 1)) |
| 151 | + #IF(%'fieldPrecision'% = '') |
| 152 | + #SET(fieldPrecision, '0') |
| 153 | + #END |
| 154 | + #UNIQUENAME(fieldCritBlockName) |
| 155 | + #SET(fieldCritBlockName, %'@name'% + 'Crit') |
| 156 | + , ' {' |
| 157 | + , ' BcdCriticalBlock ' + %'fieldCritBlockName'% + ';' |
| 158 | + , ' ' + %'pushFunction'% + '(row, ' + %'@size'% + ', ' + %'fieldPrecision'% + ');' |
| 159 | + , ' ' + %'lvalue'% + ' = DecPopReal();' |
| 160 | + , ' }' |
| 161 | + , ' row += ' + %'@size'% + ';' |
| 162 | + #ELSEIF(REGEXFIND('real', %'@type'%)) |
| 163 | + #IF(%@size% = 4) |
| 164 | + , ' ' + %'lvalue'% + ' = *(reinterpret_cast<const float*>(row));' |
| 165 | + #ELSE |
| 166 | + , ' ' + %'lvalue'% + ' = *(reinterpret_cast<const double*>(row));' |
| 167 | + #END |
| 168 | + , ' row += ' + %'@size'% + ';' |
| 169 | + #ELSEIF(REGEXFIND('unsigned', %'@type'%)) |
| 170 | + , ' ' + %'lvalue'% + ' = rtlReadUInt(row, ' + %'@size'% + ');' |
| 171 | + , ' row += ' + %'@size'% + ';' |
| 172 | + #ELSEIF(REGEXFIND('integer', %'@type'%)) |
| 173 | + , ' ' + %'lvalue'% + ' = rtlReadInt(row, ' + %'@size'% + ');' |
| 174 | + , ' row += ' + %'@size'% + ';' |
| 175 | + #ELSEIF(%'@type'% = 'boolean') |
| 176 | + , ' ' + %'lvalue'% + ' = *(reinterpret_cast<const bool*>(row));' |
| 177 | + , ' row += sizeof(bool);' |
| 178 | + #END |
| 179 | + , '' |
| 180 | + #END |
| 181 | + #END |
| 182 | + , ' }' |
| 183 | + ], |
| 184 | + %TextLayout% |
| 185 | + ); |
| 186 | + |
| 187 | + #UNIQUENAME(bodySep); |
| 188 | + LOCAL %bodySep% := DATASET |
| 189 | + ( |
| 190 | + [ |
| 191 | + '' |
| 192 | + , ' #body' |
| 193 | + ], |
| 194 | + %TextLayout% |
| 195 | + ); |
| 196 | + |
| 197 | + #UNIQUENAME(includeDefinitions); |
| 198 | + LOCAL %includeDefinitions% := %inputStructDef% + %rowExtractionCode% + %bodySep%; |
| 199 | + |
| 200 | + |
| 201 | + // Create a options for the EMBED, if necessary |
| 202 | + #UNIQUENAME(embedOptions); |
| 203 | + #SET(embedOptions, ''); |
| 204 | + |
| 205 | + #IF((STRING)embedOptionsStr != '') |
| 206 | + #APPEND(embedOptions, ' : ' + Std.Str.ToLowerCase(TRIM((STRING)embedOptionsStr, ALL))) |
| 207 | + #END |
| 208 | + |
| 209 | + #UNIQUENAME(eclResultType); |
| 210 | + #SET(eclResultType, 'UNSIGNED2'); |
| 211 | + #UNIQUENAME(cppResultType); |
| 212 | + #SET(cppResultType, 'uint16_t'); |
| 213 | + |
| 214 | + #UNIQUENAME(streamedFunctionDeclaration); |
| 215 | + LOCAL %streamedFunctionDeclaration% := DATASET |
| 216 | + ( |
| 217 | + [ |
| 218 | + %'eclResultType'% + ' ' + (STRING)functionNameStr + '(STREAMED DATASET(' + %'inputECLRecName'% + ') ' + (STRING)dsParameterNameStr + ') := EMBED(C++' + %'embedOptions'% + ')' |
| 219 | + ], |
| 220 | + %TextLayout% |
| 221 | + ); |
| 222 | + |
| 223 | + // Any C++ includes we need |
| 224 | + #UNIQUENAME(headerIncludes); |
| 225 | + LOCAL %headerIncludes% := DATASET |
| 226 | + ( |
| 227 | + [ |
| 228 | + '' |
| 229 | + #IF(%headerNeedsStdString% = 1) |
| 230 | + , ' #include <string>' |
| 231 | + #END |
| 232 | + #IF(%headerNeedsUTF% = 1) |
| 233 | + , ' #define UCHAR_TYPE uint16_t' |
| 234 | + , ' #include <unicode/unistr.h>' |
| 235 | + #END |
| 236 | + , '' |
| 237 | + ], |
| 238 | + %TextLayout% |
| 239 | + ); |
| 240 | + |
| 241 | + #UNIQUENAME(rowPtr, 'rowPtr_$'); |
| 242 | + |
| 243 | + // Code for reading each record's row from a streamed dataset |
| 244 | + #UNIQUENAME(bodyScalarResult); |
| 245 | + LOCAL %bodyScalarResult% := DATASET |
| 246 | + ( |
| 247 | + [ |
| 248 | + '' |
| 249 | + , ' ' + %'cppResultType'% + ' result;' |
| 250 | + , ' ' + %'inputECLRecName'% + ' ' + (STRING)cppRowVarNameStr + ';' |
| 251 | + , ' const byte* ' + %'rowPtr'% + ' = nullptr;' |
| 252 | + , '' |
| 253 | + , ' while ((' + %'rowPtr'% + ' = static_cast<const byte*>(' + (STRING)dsParameterNameStr + '->nextRow())))' |
| 254 | + , ' {' |
| 255 | + , ' // Populate struct ' + (STRING)cppRowVarNameStr |
| 256 | + , ' ' + %'rowExtractionFunction'% + '(' + %'rowPtr'% + ', ' + (STRING)cppRowVarNameStr + ');' |
| 257 | + , '' |
| 258 | + , ' // TODO: process data in struct ' + (STRING)cppRowVarNameStr |
| 259 | + , ' }' |
| 260 | + , '' |
| 261 | + , ' return result;' |
| 262 | + , 'ENDEMBED;' |
| 263 | + ], |
| 264 | + %TextLayout% |
| 265 | + ); |
| 266 | + |
| 267 | + #UNIQUENAME(allDefs); |
| 268 | + LOCAL %allDefs% := %streamedFunctionDeclaration% + %headerIncludes% + %includeDefinitions% + %bodyScalarResult%; |
| 269 | + |
| 270 | + #UNIQUENAME(plainResult); |
| 271 | + LOCAL %plainResult% := ROLLUP |
| 272 | + ( |
| 273 | + %allDefs%, |
| 274 | + TRUE, |
| 275 | + TRANSFORM |
| 276 | + ( |
| 277 | + RECORDOF(LEFT), |
| 278 | + SELF.text := LEFT.text + '\n' + RIGHT.text |
| 279 | + ) |
| 280 | + ); |
| 281 | + |
| 282 | + #UNIQUENAME(escapedXML); |
| 283 | + LOCAL %escapedXML% := PROJECT |
| 284 | + ( |
| 285 | + %allDefs%, |
| 286 | + TRANSFORM |
| 287 | + ( |
| 288 | + RECORDOF(LEFT), |
| 289 | + SELF.text := REGEXREPLACE('<([^>]+)>', LEFT.text, '<$1>') |
| 290 | + ) |
| 291 | + ); |
| 292 | + |
| 293 | + #UNIQUENAME(rolledUp); |
| 294 | + LOCAL %rolledUp% := ROLLUP |
| 295 | + ( |
| 296 | + %escapedXML%, |
| 297 | + TRUE, |
| 298 | + TRANSFORM |
| 299 | + ( |
| 300 | + RECORDOF(LEFT), |
| 301 | + SELF.text := LEFT.text + '<br/>' + RIGHT.text |
| 302 | + ) |
| 303 | + ); |
| 304 | + |
| 305 | + #UNIQUENAME(htmlResult); |
| 306 | + LOCAL %htmlResult% := DATASET(['<pre>' + %rolledUp%[1].text + '</pre>'], {STRING result__html}); |
| 307 | + |
| 308 | + RETURN #IF(eclWatchOutput) %htmlResult% #ELSE %plainResult% #END; |
| 309 | +ENDMACRO; |
| 310 | + |
| 311 | +//============================================================================================= |
| 312 | + |
| 313 | +MatchingLayout := RECORD |
| 314 | + // UTF8 cpe; |
| 315 | + VARSTRING cpe; |
| 316 | + BOOLEAN did_match; |
| 317 | + UNSIGNED3 num_matches; |
| 318 | + DECIMAL32_6 r4; |
| 319 | + REAL8 r8; |
| 320 | +END; |
| 321 | + |
| 322 | +generatedCode := GenerateDatasetReader |
| 323 | + ( |
| 324 | + MatchingLayout, |
| 325 | + eclWatchOutput := TRUE, |
| 326 | + embedOptionsStr := 'local,time' |
| 327 | + ); |
| 328 | + |
| 329 | +OUTPUT(generatedCode, ALL); |
0 commit comments