Line data Source code
1 : #include "otsdaq/MessageFacility/MessageFacility.h"
2 :
3 : #include <dirent.h>
4 : #include <cassert>
5 : #include <fstream>
6 : #include <iostream>
7 : #include <memory>
8 : #include <string>
9 :
10 : #include "otsdaq/Macros/StringMacros.h"
11 :
12 : // Shared test utilities
13 : #include "otsdaq/Macros/TestUtilities.h"
14 :
15 : ///
16 : /// @file otsdaq_import_tracker_test_stand.cc
17 : /// @brief
18 : /// Extracts the function definitions in the tracker Ui folder into
19 : /// the otsdaq-mu2e-tracker/otsdaq-mu2e-tracker/FEInterfaces/ folder (or any folder)
20 : ///
21 : /// Warning! it will overwrite files in the output folder with the same names!
22 : ///
23 : /// usage:
24 : /// otsdaq_import_tracker_test_stand <import Ui path> <export FEInterface path>
25 : ///
26 : /// Created by rrivera, December 2025
27 : ///
28 :
29 : using namespace ots;
30 :
31 : //==============================================================================
32 : /// @brief Modifies the source code string for the FEInterface as follows:
33 : /// - Replaces instances of the fDtc with getDTC()
34 : /// @param source the source code to modify
35 : /// @param isHeader whether the source is a header file
36 : /// @param outputFile
37 0 : std::string modifySource(std::string& source, bool isHeader = false)
38 : {
39 : std::vector<std::pair<std::string, std::string>> replacements = {
40 : {"fDtc", "getDTC()"},
41 : {"getDTC()ID", "fDtcID"}, // fix accidental replacement of member variable
42 :
43 : {"TrkSpiData_t", "trkdaq::TrkSpiData_t"},
44 : {"roc_data_t", "DTCLib::roc_data_t"},
45 : {"DTC_Link_ID", "DTCLib::DTC_Link_ID"},
46 : {"DTC_SubEvent", "DTCLib::DTC_SubEvent"},
47 : {"DTC_EventWindowTag", "DTCLib::DTC_EventWindowTag"},
48 : {"roc_address_t", "DTCLib::roc_address_t"},
49 : {"DTC_LinkEnableMode", "DTCLib::DTC_LinkEnableMode"},
50 : {"DTC_Link_ALL", "DTCLib::DTC_Link_ALL"},
51 : {"EventMode()", "((((int64_t)fOnSpill) << 32) | ((int64_t)fEventMode))"},
52 : {"DTC_ROC_Links", "DTCLib::DTC_ROC_Links"},
53 : {"ControlRoc_DeviceID_t", "trkdaq::ControlRoc_DeviceID_t"},
54 : {"TrkSpiDataNWords", "trkdaq::TrkSpiDataNWords"},
55 :
56 : // {"RocRegisters", "trkdaq::RocRegisters"},
57 : {"trkdaq::RocRegisters", "RocRegisters"},
58 : {"Gettrkdaq::RocRegisters", "GetRocRegisters"}, // fix accidental replacement
59 : {"GetConvertedtrkdaq::RocRegisters",
60 : "GetConvertedRocRegisters"}, // fix accidental replacement
61 :
62 : {"roc_fw_data_t", "trkdaq::roc_fw_data_t"},
63 : {"roc_fw_version_t", "trkdaq::roc_fw_version_t"},
64 : {"RocFwData_t", "trkdaq::RocFwData_t"},
65 : {"ControlRoc_DigiRW_Input_t", "trkdaq::ControlRoc_DigiRW_Input_t"},
66 : {"ControlRoc_DigiRW_Output_t", "trkdaq::ControlRoc_DigiRW_Output_t"},
67 : {"ControlRoc_Read_Input_t0", "trkdaq::ControlRoc_Read_Input_t0"},
68 : {"ControlRoc_Read_Output_t0", "trkdaq::ControlRoc_Read_Output_t0"},
69 : {"ControlRoc_Rates_t", "trkdaq::ControlRoc_Rates_t"},
70 : {"REG_", "trkdaq::REG_"},
71 :
72 : {"trkdaq::REG_STATUS", "REG_STATUS"},
73 :
74 : {"roc_serial_t", "std::string"},
75 :
76 : {"vector", "std::vector"},
77 : {"string", "std::string"},
78 : {"to_std::string", "std::to_string"}, // fix accidental replacement
79 : {"ifstream", "std::ifstream"},
80 : {"ofstream", "std::ofstream"},
81 : {"fstream", "std::fstream"},
82 : {"std::istd::fstream", "std::ifstream"}, // fix accidental replacement
83 : {"cout", "std::cout"},
84 : {"endl", "std::endl"},
85 : {"stringstream", "std::stringstream"},
86 : {"hex", "std::hex"},
87 : {"dec", "std::dec"},
88 :
89 : {"override", ""},
90 :
91 : {"trkdaq::trkdaq::", "trkdaq::"},
92 : {"std::std::std::", "std::"},
93 : {"std::std::", "std::"},
94 : {"DTCLib::DTCLib::", "DTCLib::"},
95 0 : };
96 : std::vector<std::pair<std::string, std::string>> functionReplacements = {
97 : {"ConfigureJA", "Ui_base_ConfigureJA"},
98 : {"InitEmulatedCFOReadoutMode", "Ui_base_InitEmulatedCFOReadoutMode"},
99 : {"InitExternalCFOReadoutMode", "Ui_base_InitExternalCFOReadoutMode"},
100 : {"ResetLinks", "Ui_base_ResetLinks"},
101 : {"SetLinkMask", "Ui_base_SetLinkMask"},
102 :
103 : {"ResetLink", "Ui_ResetLink"},
104 :
105 : {"Ui_base_Ui_ResetLinks", "Ui_base_ResetLinks"}, // fix accidental replacement
106 :
107 : {"InitReadout", "Ui_InitReadout"},
108 : {"InitRocReadoutMode", "Ui_InitRocReadoutMode"},
109 : {"LaunchRunPlanEmulatedCfo", "Ui_LaunchRunPlanEmulatedCfo"},
110 : {"ReadRegister", "Ui_ReadRegister"},
111 : {"ReadSpiData", "Ui_ReadSpiData"},
112 : {"RocConfigurePatternMode", "Ui_RocConfigurePatternMode"},
113 : {"ResetRoc", "Ui_ResetRoc"},
114 : {"RocSetDataVersion", "Ui_RocSetDataVersion"},
115 : {"ReadSubevents", "Ui_ReadSubevents"},
116 : {"ReadROCBlockEnsured", "Ui_ReadROCBlockEnsured"},
117 : {"ReadDeviceID", "Ui_ReadDeviceID"},
118 : {"ReadSerialNumber", "Ui_ReadSerialNumber"},
119 : {"FindAlignment", "Ui_FindAlignment"},
120 : {"FindAlignments", "Ui_FindAlignments"},
121 : {"SetBit", "Ui_SetBit"},
122 : {"SetupCfoInterface", "Ui_SetupCfoInterface"},
123 : {"ValidateDigiPatterns", "Ui_ValidateDigiPatterns"},
124 : {"ValidateFixedPatterns", "Ui_ValidateFixedPatterns"},
125 : {"ValidateVarPatterns", "Ui_ValidateVarPatterns"},
126 : {"MonicaDigiClear", "Ui_MonicaDigiClear"},
127 : {"MonicaVarLinkConfig", "Ui_MonicaVarLinkConfig"},
128 : {"MonicaVarPatternConfig", "Ui_MonicaVarPatternConfig"},
129 : {"GetRocRegisters", "Ui_GetRocRegisters"},
130 : {"ProgramAndQueryThreshold", "Ui_ProgramAndQueryThreshold"},
131 : {"FindThreshold", "Ui_FindThreshold"},
132 : {"RocBlockRead", "Ui_RocBlockRead"},
133 :
134 : {"PrintBuffer", "Ui_print_PrintBuffer"},
135 : {"PrintRocRegister", "Ui_print_PrintRocRegister"},
136 : {"PrintRocRegister2", "Ui_print_PrintRocRegister2"},
137 : {"Ui_print_Ui_print_", "Ui_print_"}, // fix accidental replacement
138 :
139 : {"ControlRoc_ReadSpi", "Ui_ControlRoc_ControlRoc_ReadSpi"},
140 : {"ConvertSpiData", "Ui_ControlRoc_ConvertSpiData"},
141 : {"ControlRoc_Ui_ReadDeviceID", "Ui_ControlRoc_ControlRoc_ReadDeviceID"},
142 : {"ControlRoc_ReadGitCommit", "Ui_ControlRoc_ControlRoc_ReadGitCommit"},
143 : {"ControlRoc_SetThreshold", "Ui_ControlRoc_ControlRoc_SetThreshold"},
144 : {"ControlRoc_ReadThresholds", "Ui_ControlRoc_ControlRoc_ReadThresholds"},
145 : {"ControlRoc_ReadSettings", "Ui_ControlRoc_ControlRoc_ReadSettings"},
146 : {"ControlRoc_PrintThresholds", "Ui_ControlRoc_ControlRoc_PrintThresholds"},
147 :
148 : {"SpiWriteRecord", "Ui_ProgramRoc_SpiWriteRecord"},
149 : {"SpiLoadImage", "Ui_ProgramRoc_SpiLoadImage"},
150 : {"SpiIapIndex", "Ui_ProgramRoc_SpiIapIndex"},
151 : {"SpiWriteDirectory", "Ui_ProgramRoc_SpiWriteDirectory"},
152 : {"SpiClearMemory", "Ui_ProgramRoc_SpiClearMemory"},
153 :
154 0 : };
155 :
156 0 : for(const auto& [oldStr, newStr] : replacements)
157 : {
158 0 : size_t pos = 0;
159 0 : while((pos = source.find(oldStr, pos)) != std::string::npos)
160 : {
161 0 : source.replace(pos, oldStr.length(), newStr);
162 0 : pos += newStr.length();
163 : }
164 : }
165 0 : if(!isHeader)
166 : {
167 0 : for(const auto& [oldStr, newStr] : functionReplacements)
168 : {
169 0 : size_t pos = 0;
170 0 : while((pos = source.find(oldStr, pos)) != std::string::npos)
171 : {
172 0 : source.replace(pos, oldStr.length(), newStr);
173 0 : pos += newStr.length();
174 : }
175 : }
176 : }
177 0 : return source;
178 0 : } // end modifySource()
179 :
180 : //==============================================================================
181 : /// @brief Returns true if the function arguments in the function header are simple enough
182 : /// (i.e. int, string) for converting to FE macros
183 : /// Also fills in the argTypes, argNames, argDefaults, outputTypes, outputNames
184 : /// vectors.
185 : /// @param functionHeader the full function header
186 0 : bool validateArgsForFEMacro(const std::string& functionHeader,
187 : const std::string& returnVal,
188 : std::vector<std::string>& argTypes,
189 : std::vector<std::string>& argNames,
190 : std::vector<std::string>& argDefaults,
191 : std::vector<std::string>& outputTypes,
192 : std::vector<std::string>& outputNames,
193 : bool ignoreAllowedTypes = false)
194 : {
195 0 : size_t argTypePos = functionHeader.find('(');
196 0 : if(argTypePos == std::string::npos)
197 : {
198 0 : __SS__ << "ERROR: could not find '(' in function header: " << functionHeader
199 0 : << __E__;
200 0 : __SS_THROW__;
201 0 : }
202 0 : size_t argEndPos = functionHeader.find(')', argTypePos);
203 0 : if(argEndPos == std::string::npos)
204 : {
205 0 : __SS__ << "ERROR: could not find ')' in function header: " << functionHeader
206 0 : << __E__;
207 0 : __SS_THROW__;
208 0 : }
209 :
210 : // decide if there is an output return valu
211 : // for now, only handle void return type with no outputs
212 0 : if(!ignoreAllowedTypes && returnVal != "void" && returnVal != "int" &&
213 0 : returnVal != "unsigned int" && returnVal != "std::string" && returnVal != "bool" &&
214 0 : returnVal != "double" && returnVal != "float" &&
215 0 : returnVal != "std::vector<DTCLib::roc_data_t>" &&
216 0 : returnVal != "std::vector<std::string>" && returnVal != "std::vector<uint32_t>" &&
217 0 : returnVal != "std::vector<float>" && returnVal != "size_t" &&
218 0 : returnVal != "uint16_t" && returnVal != "uint32_t")
219 : {
220 0 : __COUT_ERR__ << "- Return type '" << returnVal
221 0 : << "' is not supported for FE Macro conversion in function header: "
222 0 : << functionHeader << std::endl;
223 0 : return false;
224 : }
225 0 : if(returnVal != "void")
226 : {
227 0 : outputTypes.push_back(returnVal);
228 0 : outputNames.push_back("Result");
229 : }
230 : else // indicate no return value
231 : {
232 0 : outputTypes.push_back("void");
233 0 : outputNames.push_back("");
234 : }
235 :
236 : std::string argList =
237 0 : functionHeader.substr(argTypePos + 1, argEndPos - argTypePos - 1);
238 0 : __COUTTV__(argList);
239 :
240 : // remove any comments from argList
241 : while(1)
242 : {
243 0 : size_t commentPos = argList.find("//");
244 0 : if(commentPos == std::string::npos)
245 0 : break;
246 0 : size_t endOfLinePos = argList.find('\n', commentPos);
247 0 : if(endOfLinePos == std::string::npos)
248 0 : endOfLinePos = argList.size();
249 0 : argList.erase(commentPos, endOfLinePos - commentPos);
250 0 : } // end comment removal loop
251 :
252 : // split by commas
253 0 : std::vector<std::string> args = StringMacros::getVectorFromString(argList, {','});
254 0 : for(const auto& arg : args)
255 : {
256 0 : __COUTTV__(arg);
257 :
258 0 : if(!arg.size())
259 0 : break; // skip empty args (possible for no args)
260 :
261 : std::vector<std::string> argParts = StringMacros::getVectorFromString(
262 0 : arg, {' ', '\t', '\n'}, {} /* whitespace */);
263 0 : if(argParts.size() < 2)
264 : {
265 0 : __COUT_ERR__ << "Could not parse argument '"
266 0 : << StringMacros::vectorToString(argParts)
267 0 : << "' in function header: " << functionHeader << std::endl;
268 0 : return false;
269 : }
270 :
271 0 : size_t i = 0;
272 0 : bool foundEquals = false;
273 0 : bool isConst = false;
274 0 : bool isOutputByReference = false;
275 0 : std::string argType;
276 0 : for(const auto& part : argParts)
277 : {
278 0 : __COUTT__ << "pre-part " << part << " i=" << i << std::endl;
279 :
280 0 : if(part.size() == 0)
281 0 : continue; // skip empty parts
282 :
283 0 : if(part.size() && (part == " " || part == "\t" || part == "\n"))
284 0 : continue; // skip whitespace parts
285 :
286 0 : __COUTT__ << "part " << part << " i=" << i << std::endl;
287 :
288 0 : if(i == 0)
289 : {
290 0 : argType = part; // first part is type
291 0 : __COUTTV__(argType);
292 0 : if(argType == "const")
293 : {
294 0 : isConst = true;
295 0 : continue;
296 : }
297 0 : __COUTTV__(argType);
298 :
299 : // check if argType is simple enough
300 0 : if(!ignoreAllowedTypes && argType != "int" && argType != "uint" &&
301 0 : argType != "unsigned int" && argType != "std::string" &&
302 0 : argType != "bool" && argType != "double" && argType != "float" &&
303 0 : argType != "DTCLib::DTC_Link_ID" &&
304 0 : (argType != "DTCLib::DTC_Link_ID&" || !isConst) &&
305 0 : argType != "DTCLib::roc_address_t&" && argType != "std::ostream&" &&
306 0 : (argType != "std::vector<DTCLib::roc_data_t>&" || isConst) &&
307 0 : (argType != "std::vector<uint16_t>&" || isConst) &&
308 0 : (argType != "std::vector<uint16_t>*" || isConst) &&
309 0 : argType != "size_t" && argType != "uint16_t" && argType != "uint32_t")
310 : {
311 0 : __COUT_ERR__ << "- Argument type '" << (isConst ? "const " : "")
312 0 : << argType
313 : << "' is not supported for FE Macro conversion in "
314 0 : "function header: "
315 0 : << functionHeader << std::endl;
316 0 : return false;
317 : }
318 0 : __COUTTV__(argType);
319 :
320 : // do not add "const," since FE Macro must set parameter to pass (and
321 : // argType search cannot overload const/no-const anyway)
322 : // if(isConst)
323 : // argType = "const " + argType;
324 :
325 0 : if(argType == "std::vector<uint16_t>&" ||
326 0 : argType == "std::vector<uint16_t>*" || argType == "std::ostream&" ||
327 0 : argType == "std::vector<roc_data_t>&")
328 : {
329 0 : __COUTT__ << " -- Treating " << argType << " as output parameter."
330 0 : << std::endl;
331 0 : isOutputByReference = true;
332 : }
333 :
334 0 : if(isOutputByReference)
335 0 : argTypes.push_back(
336 0 : std::string("out") +
337 0 : (argType[argType.size() - 1] == '*'
338 : ? "*"
339 0 : : "")); // mark as output by reference or by pointer
340 : else
341 0 : argTypes.push_back(argType);
342 0 : __COUTTV__(argTypes.back());
343 : }
344 0 : else if(i == 1)
345 : {
346 0 : if(part.find('=') != std::string::npos)
347 : {
348 0 : foundEquals = true;
349 :
350 0 : __COUTT__ << "Found default value in name part: " << part
351 0 : << std::endl;
352 0 : auto equalParts = StringMacros::getVectorFromString(part, {'='});
353 0 : if(equalParts.size() != 2)
354 : {
355 0 : __COUT_ERR__ << "Could not parse argument with = in '"
356 0 : << StringMacros::vectorToString(argParts)
357 0 : << "' in function header: " << functionHeader
358 0 : << std::endl;
359 0 : return false;
360 : }
361 0 : argNames.push_back(equalParts[0]); // second part is name
362 :
363 0 : if(equalParts[1].size() == 0) // case is 'name= Default'
364 : {
365 0 : __COUTT__ << "No default value YET after = in name part: " << part
366 0 : << std::endl;
367 : }
368 : else
369 : {
370 0 : __COUTT__ << "Found default value after = in name part: " << part
371 0 : << std::endl;
372 0 : argDefaults.push_back(equalParts[1]); // default value
373 0 : __COUTTV__(argDefaults.back());
374 : }
375 0 : }
376 : else
377 : {
378 0 : __COUTT__ << "No default value in name part: " << part << std::endl;
379 0 : argNames.push_back(part); // second part is name
380 : }
381 0 : __COUTTV__(argNames.back());
382 :
383 0 : if(isOutputByReference)
384 : {
385 0 : outputTypes.push_back(argType);
386 0 : outputNames.push_back(argNames.back());
387 : }
388 : }
389 0 : else if(i > 1 && !foundEquals) // possible 'name =Default' here
390 : {
391 0 : if(part.size() > 1 && part[0] == '=') // handle case of no spaces around
392 : // =
393 : {
394 0 : argDefaults.push_back(part.substr(1)); // fourth part is default
395 : // value
396 0 : __COUTTV__(argDefaults.back());
397 : }
398 0 : else if(part == "=")
399 : {
400 0 : foundEquals = true; // next part is default value
401 0 : __COUTTV__(foundEquals);
402 : }
403 : else
404 : {
405 0 : __COUT_ERR__ << "Could not parse argument missing = in '"
406 0 : << StringMacros::vectorToString(argParts)
407 0 : << "' in function header: " << functionHeader
408 0 : << std::endl;
409 0 : return false;
410 : }
411 0 : }
412 0 : else if(i > 1 && foundEquals) // fourth part is default value
413 : {
414 0 : if(argDefaults.size() < argNames.size())
415 : {
416 0 : argDefaults.push_back(part);
417 0 : __COUTTV__(argDefaults.back());
418 : }
419 : else
420 : {
421 0 : __COUT_ERR__
422 0 : << "Could not parse argument with multiple default values in '"
423 0 : << StringMacros::vectorToString(argParts)
424 0 : << "' in function header: " << functionHeader << std::endl;
425 0 : return false;
426 : }
427 : }
428 :
429 0 : ++i;
430 : } // end art parts loop
431 :
432 0 : if(argDefaults.size() < argNames.size())
433 : {
434 0 : argDefaults.push_back(""); // no default value
435 0 : __COUTTV__(argDefaults.back());
436 : }
437 0 : else if(argDefaults.size() > argNames.size())
438 : {
439 0 : __COUT_ERR__ << "Could not parse argument with multiple default values in '"
440 0 : << StringMacros::vectorToString(argParts)
441 0 : << "' in function header: " << functionHeader << std::endl;
442 0 : return false;
443 : }
444 0 : } // end main arg loop
445 :
446 : // if here, all args are simple enough
447 0 : __COUTTV__(StringMacros::vectorToString(argTypes));
448 0 : __COUTTV__(StringMacros::vectorToString(argNames));
449 0 : __COUTTV__(StringMacros::vectorToString(argDefaults));
450 0 : __COUTTV__(StringMacros::vectorToString(outputTypes));
451 0 : __COUTTV__(StringMacros::vectorToString(outputNames));
452 :
453 0 : return true;
454 0 : } // end validateArgsForFEMacro()
455 :
456 : //==============================================================================
457 : /// @brief Extracts the declared function header from the full function header
458 : /// @param functionHeader the full function header
459 : /// @param sourceFile the source file the function is from
460 0 : std::string getDeclaredFunctionHeader(const std::string& functionHeader,
461 : const std::string& sourceFile)
462 : {
463 : // general case
464 0 : size_t parenPos = functionHeader.find('(');
465 0 : if(parenPos == std::string::npos)
466 : {
467 0 : __SS__ << "ERROR: could not find '(' in function header: " << functionHeader
468 0 : << __E__;
469 0 : __SS_THROW__;
470 0 : }
471 0 : std::string beforeParen = functionHeader.substr(0, parenPos);
472 0 : __COUTTV__(beforeParen);
473 :
474 : // get arg list to match when finding declaration in header file
475 0 : std::vector<std::string> argTypes, argNames, argDefaults, outputTypes, outputNames;
476 : { // extract arg types (do not modify types, since comparing against unmodified
477 : // header)
478 0 : if(!validateArgsForFEMacro(functionHeader,
479 : "void" /* dummy return val arg */,
480 : argTypes,
481 : argNames,
482 : argDefaults,
483 : outputTypes,
484 : outputNames,
485 : true /* ignoreAllowedTypes */))
486 : {
487 0 : __SS__ << "ERROR: could not validate args for function header: "
488 0 : << functionHeader << __E__;
489 0 : __SS_THROW__;
490 0 : }
491 : }
492 :
493 : // find in file the function name
494 0 : std::ifstream in(sourceFile);
495 0 : if(!in)
496 : {
497 0 : __SS__ << "\n\nERROR! Could not open file at " << sourceFile
498 0 : << " - error: " << errno << " - " << strerror(errno) << __E__;
499 0 : __SS_THROW__;
500 0 : }
501 : std::string fileContents((std::istreambuf_iterator<char>(in)),
502 0 : std::istreambuf_iterator<char>());
503 : // fileContents now contains the full contents of sourceFile
504 0 : size_t funcNamePos = 0;
505 : while(1) // search for function name loop in header
506 : {
507 0 : funcNamePos = fileContents.find(beforeParen, funcNamePos + 1);
508 0 : if(funcNamePos == std::string::npos)
509 : {
510 0 : __SS__ << "\nERROR: could not find function name '" << beforeParen
511 0 : << "' in source file: " << sourceFile << __E__;
512 0 : __SS_THROW__;
513 0 : }
514 0 : __COUTTV__(fileContents.substr(funcNamePos, 50));
515 : // make sure found instance is not a comment or header with similar name
516 0 : size_t prevNewLine = fileContents.rfind("\n", funcNamePos);
517 0 : size_t prevComment = fileContents.rfind("//", funcNamePos);
518 0 : if(prevComment != std::string::npos && prevNewLine != std::string::npos &&
519 : prevComment > prevNewLine)
520 : {
521 0 : __COUTT__ << "Found function name in comment, continuing search..."
522 0 : << std::endl;
523 0 : continue; // then found function name is in comment
524 0 : }
525 :
526 : // make sure next character is whitespace or '(' for arg list
527 0 : size_t charAfterFuncNamePos = funcNamePos + beforeParen.size();
528 0 : if(charAfterFuncNamePos >= fileContents.size() ||
529 0 : (fileContents[charAfterFuncNamePos] != ' ' &&
530 0 : fileContents[charAfterFuncNamePos] != '\t' &&
531 0 : fileContents[charAfterFuncNamePos] != '\n' &&
532 0 : fileContents[charAfterFuncNamePos] != '('))
533 : {
534 0 : __COUTT__
535 0 : << "Found function name as part of another word, continuing search..."
536 0 : << std::endl;
537 0 : continue; // then found function name is part of another word
538 0 : }
539 :
540 : // make sure there is an arg list after function name
541 0 : size_t nextNewline = fileContents.find("\n", funcNamePos);
542 0 : size_t nextParenthesis = fileContents.find("(", funcNamePos);
543 :
544 0 : if(nextParenthesis == std::string::npos ||
545 0 : (nextNewline != std::string::npos && nextParenthesis > nextNewline))
546 : {
547 0 : __COUTT__ << "Found function name without arg list, continuing search..."
548 0 : << std::endl;
549 0 : continue; // then found function name is not a function definition
550 0 : }
551 :
552 : // make sure all arg types exist to match function definition (Note: arg name
553 : // mismatch is allowed in C++)
554 0 : size_t argEndPos = fileContents.find(')', nextParenthesis);
555 0 : if(argEndPos == std::string::npos)
556 : {
557 0 : __COUTT__ << "Found function name without arg list end, continuing search..."
558 0 : << std::endl;
559 0 : continue; // then found function name is not a function definition
560 0 : }
561 0 : size_t argTypePos = nextParenthesis;
562 0 : size_t maxArgTypePos = nextParenthesis;
563 0 : bool mismatch = false;
564 0 : for(const auto& argType : argTypes) // input arg types confirmation loop
565 : {
566 0 : if(argType.find("out") == 0) // skip output by reference args
567 0 : continue;
568 0 : size_t foundArgTypePos = argTypePos;
569 : while(1)
570 : {
571 0 : foundArgTypePos = fileContents.find(argType, argTypePos);
572 0 : if(foundArgTypePos == std::string::npos || foundArgTypePos > argEndPos)
573 : {
574 0 : __COUTT__ << "Could not find input arg type '" << argType
575 0 : << "' in function definition, continuing search..."
576 0 : << std::endl;
577 0 : mismatch = true;
578 0 : break; // then found function name is not the correct function
579 : // definition
580 : }
581 0 : __COUTTV__(argType);
582 0 : size_t charAfterPos = foundArgTypePos + argType.size();
583 : // make sure it is clean argType match (i.e. not part of another word)
584 : // must be , or whitespace or end before and after
585 0 : if(foundArgTypePos != nextParenthesis)
586 : {
587 0 : char charBefore = fileContents[foundArgTypePos - 1];
588 0 : if(charBefore != ',' && charBefore != ' ' && charBefore != '\t' &&
589 0 : charBefore != '\n' && charBefore != '(' && charBefore != ':')
590 : {
591 0 : __COUTT__ << "Found input arg type '" << argType
592 0 : << "' as part of another word, continuing search..."
593 0 : << fileContents.substr(foundArgTypePos - 1, 20)
594 0 : << std::endl;
595 0 : argTypePos = charAfterPos;
596 0 : continue; // then keep looking for the argType
597 0 : }
598 : }
599 :
600 0 : if(charAfterPos < fileContents.size())
601 : {
602 0 : char charAfter = fileContents[charAfterPos];
603 0 : if(charAfter != ',' && charAfter != ' ' && charAfter != '\t' &&
604 0 : charAfter != '\n' && charAfter != ')')
605 : {
606 0 : __COUTT__ << "Found input arg type '" << argType
607 0 : << "' as part of another word, continuing search..."
608 0 : << fileContents.substr(foundArgTypePos - 1, 20)
609 0 : << std::endl;
610 0 : argTypePos = charAfterPos;
611 0 : continue; // then keep looking for the argType
612 0 : }
613 : }
614 0 : break; // argType found cleanly
615 0 : } // end argType find loop
616 0 : argTypePos = fileContents.find(',', foundArgTypePos + argType.size());
617 0 : __COUTTV__(argTypePos);
618 0 : if(argTypePos == std::string::npos || argTypePos > argEndPos)
619 0 : argTypePos = argEndPos; // move to end of arg list if no more
620 : else
621 0 : __COUTTV__(fileContents.substr(argTypePos, 20));
622 0 : maxArgTypePos = argTypePos;
623 0 : __COUTTV__(maxArgTypePos);
624 0 : __COUTTV__(fileContents.substr(maxArgTypePos, 20));
625 : } // end input arg types confirmation loop
626 0 : if(mismatch)
627 0 : continue;
628 :
629 0 : argTypePos = nextParenthesis;
630 0 : mismatch = false;
631 0 : bool isFirst = true;
632 0 : for(const auto& argType : outputTypes) // output arg types confirmation loop
633 : {
634 0 : if(isFirst)
635 : {
636 0 : isFirst = false;
637 0 : continue; // skip return value
638 : }
639 0 : size_t foundArgTypePos = argTypePos;
640 : while(1)
641 : {
642 0 : foundArgTypePos = fileContents.find(argType, argTypePos);
643 0 : if(foundArgTypePos == std::string::npos || foundArgTypePos > argEndPos)
644 : {
645 0 : __COUTT__ << "Could not find output arg type '" << argType
646 0 : << "' in function definition, continuing search..."
647 0 : << std::endl;
648 0 : mismatch = true;
649 0 : break; // then found function name is not the correct function
650 : // definition
651 : }
652 0 : __COUTTV__(argType);
653 :
654 0 : size_t charAfterPos = foundArgTypePos + argType.size();
655 : // make sure it is clean argType match (i.e. not part of another word)
656 : // must be , or whitespace or end before and after
657 0 : if(foundArgTypePos != nextParenthesis)
658 : {
659 0 : char charBefore = fileContents[foundArgTypePos - 1];
660 0 : if(charBefore != ',' && charBefore != ' ' && charBefore != '\t' &&
661 0 : charBefore != '\n' && charBefore != '(')
662 : {
663 0 : __COUTT__ << "Found input arg type '" << argType
664 0 : << "' as part of another word, continuing search..."
665 0 : << fileContents.substr(foundArgTypePos - 1, 20)
666 0 : << std::endl;
667 0 : argTypePos = charAfterPos;
668 0 : continue; // then keep looking for the argType
669 0 : }
670 : }
671 0 : if(charAfterPos < fileContents.size())
672 : {
673 0 : char charAfter = fileContents[charAfterPos];
674 0 : if(charAfter != ',' && charAfter != ' ' && charAfter != '\t' &&
675 0 : charAfter != '\n' && charAfter != ')')
676 : {
677 0 : __COUTT__ << "Found input arg type '" << argType
678 0 : << "' as part of another word, continuing search..."
679 0 : << fileContents.substr(foundArgTypePos - 1, 20)
680 0 : << std::endl;
681 0 : argTypePos = charAfterPos;
682 0 : continue; // then keep looking for the argType
683 0 : }
684 : }
685 0 : break; // argType found cleanly
686 0 : } // end argType find loop
687 0 : argTypePos = fileContents.find(',', foundArgTypePos + argType.size());
688 0 : __COUTTV__(argTypePos);
689 0 : if(argTypePos == std::string::npos || argTypePos > argEndPos)
690 0 : argTypePos = argEndPos; // move to end of arg list if no more
691 : else
692 0 : __COUTTV__(fileContents.substr(argTypePos, 20));
693 0 : if(argTypePos > maxArgTypePos)
694 : {
695 0 : maxArgTypePos = argTypePos;
696 0 : __COUTTV__(maxArgTypePos);
697 0 : __COUTTV__(fileContents.substr(maxArgTypePos, 20));
698 : }
699 : } // end output arg types confirmation loop
700 0 : if(mismatch)
701 0 : continue;
702 :
703 0 : __COUTTV__(maxArgTypePos);
704 0 : __COUTTV__(fileContents.substr(maxArgTypePos, 20));
705 :
706 : // confirm no more parameters exist that would indicate overload function mismatch
707 0 : size_t nextComma = fileContents.find(',', maxArgTypePos);
708 0 : if(nextComma != std::string::npos && nextComma < argEndPos)
709 : {
710 0 : __COUTT__ << "Found extra arg type after expected types, continuing search..."
711 0 : << std::endl;
712 0 : continue; // then found function name is not the correct function definition
713 0 : }
714 :
715 : // else found function name is valid, so break out of search loop
716 0 : break;
717 0 : } // end search for function name loop
718 :
719 : // find semicolon after function name
720 0 : size_t semicolonPos = funcNamePos;
721 : while(1)
722 : {
723 0 : semicolonPos = fileContents.find(';', semicolonPos + 1);
724 0 : if(semicolonPos == std::string::npos)
725 : {
726 0 : __SS__ << "ERROR: could not find ';' after function name in source file: "
727 0 : << beforeParen << " in file " << sourceFile << __E__;
728 0 : __SS_THROW__;
729 0 : }
730 :
731 : // ignore semicolons in comments
732 0 : size_t prevNewLine = fileContents.rfind("\n", semicolonPos);
733 0 : size_t prevComment = fileContents.rfind("//", semicolonPos);
734 0 : if(prevComment == std::string::npos ||
735 0 : (prevNewLine != std::string::npos && prevComment < prevNewLine))
736 : break; // then ; is not in comment
737 : // else is in comment, so continue searching
738 0 : } // end search for semicolon loop
739 :
740 : // extract declared function header
741 : std::string declaredFunctionHeader =
742 0 : fileContents.substr(funcNamePos, semicolonPos - funcNamePos);
743 0 : __COUTTV__(declaredFunctionHeader);
744 0 : return declaredFunctionHeader;
745 0 : } // end getDeclaredFunctionHeader()
746 :
747 : //==============================================================================
748 : /// @brief Imports the tracker test stand UI files and modifies them for the FEInterface
749 : /// @param argc
750 : /// @param argv
751 0 : void ImportTrackerTestStand(int argc, char* argv[])
752 : {
753 0 : std::cout << "=================================================\n";
754 0 : std::cout << "======= ImportTrackerTestStand ===========\n";
755 0 : std::cout << "=================================================\n";
756 0 : __COUT__ << "\nImporting Tracker Test Stand!" << std::endl;
757 :
758 0 : __COUT_INFO__
759 0 : << "\n\nusage: two argumenst:\n\t <import Ui path> <export FEInterface path> \n\n"
760 0 : << std::endl;
761 :
762 0 : __COUT_INFO__ << "argc = " << argc << std::endl;
763 0 : for(int i = 0; i < argc; i++)
764 0 : __COUT_INFO__ << "argv[" << i << "] = " << argv[i] << std::endl;
765 :
766 0 : if(argc != 3)
767 : {
768 0 : __COUT_ERR__ << "Error! Must provide two parameters.\n\n" << std::endl;
769 0 : return;
770 : }
771 :
772 0 : std::string importPath = argv[1];
773 0 : __COUTV__(importPath);
774 0 : std::string exportPath = argv[2];
775 0 : __COUTV__(exportPath);
776 :
777 : DIR* dpi;
778 0 : if((dpi = opendir(importPath.c_str())) == 0)
779 : {
780 0 : __COUT_ERR__ << "ERROR:(" << errno
781 0 : << "). Can't open Ui directory for import: " << importPath
782 0 : << std::endl;
783 0 : exit(0);
784 : }
785 0 : closedir(dpi);
786 :
787 : DIR* dpo;
788 0 : if((dpo = opendir(exportPath.c_str())) == 0)
789 : {
790 0 : __COUT_ERR__ << "ERROR:(" << errno
791 0 : << "). Can't open FEInterface directory for export: " << exportPath
792 0 : << std::endl;
793 0 : exit(0);
794 : }
795 0 : closedir(dpo);
796 :
797 : // return;
798 :
799 : std::vector<std::pair<std::string /* file */, std::string /* error message */>>
800 0 : importErrors;
801 :
802 : // usually at otsdaq-mu2e-tracker/otsdaq-mu2e-tracker/Ui/DtcInterface.cc
803 : std::vector<std::string> filesToImport = {"DtcInterfaceBase.cc",
804 : "DtcInterface.cc",
805 : "DtcInterface_print.cc",
806 : "DtcInterface_ProgramRoc.cc",
807 0 : "DtcInterface_ControlRoc.cc"};
808 : std::vector<std::string> headerFilesToImport = {"DtcInterfaceBase.hh",
809 : "DtcInterface.hh",
810 : "DtcInterface.hh",
811 : "DtcInterface.hh",
812 0 : "DtcInterface.hh"};
813 : std::vector<std::string> prepend = {
814 0 : "Ui_base", "Ui", "Ui_print", "Ui_ProgramRoc", "Ui_ControlRoc"};
815 0 : for(size_t i = 0; i < filesToImport.size(); i++)
816 : {
817 0 : std::string importFile = importPath + "/" + filesToImport[i];
818 0 : __COUTV__(importFile);
819 0 : __COUTV__(prepend[i]);
820 : try
821 : {
822 0 : std::ifstream in(importFile);
823 0 : if(!in)
824 : {
825 0 : __SS__ << "\n\nERROR! Could not open file at " << importFile
826 0 : << ". Error: " << errno << " - " << strerror(errno) << __E__;
827 0 : __SS_THROW__;
828 0 : }
829 : // modify import file to be consistent by path location (inserted in comments
830 : // and printouts, which can cause git diffs), starting from
831 : // otsdaq-mu2e-tracker/
832 0 : size_t tpos = importFile.rfind("otsdaq-mu2e-tracker"); // find last instance
833 0 : if(tpos == std::string::npos)
834 0 : importFile = "otsdaq-mu2e-tracker/" + importFile;
835 : else
836 0 : importFile = importFile.substr(tpos);
837 :
838 : std::string fileContents((std::istreambuf_iterator<char>(in)),
839 0 : std::istreambuf_iterator<char>());
840 : // fileContents now contains the full contents of importFile
841 :
842 : std::string outputFilePath =
843 0 : exportPath + "/ROCTrackerInterface_" + prepend[i] + ".cc";
844 0 : std::ofstream outputFile(outputFilePath);
845 0 : if(!outputFile.is_open())
846 : {
847 0 : __SS__ << "\n\nERROR! Could not open output file at " << outputFilePath
848 0 : << __E__;
849 0 : __SS_THROW__;
850 0 : }
851 : std::string outputHeaderPath =
852 0 : exportPath + "/ROCTrackerInterface_" + prepend[i] + ".hxx";
853 0 : std::ofstream outputHeaderFile(outputHeaderPath);
854 0 : if(!outputHeaderFile.is_open())
855 : {
856 0 : __SS__ << "\n\nERROR! Could not open header output file at "
857 0 : << outputHeaderPath << __E__;
858 0 : __SS_THROW__;
859 0 : }
860 0 : std::string outputFeMacroDeclarePath = exportPath + "/ROCTrackerInterface_" +
861 0 : prepend[i] + "_declareFEMacros.hxx";
862 0 : std::ofstream outputFeMacroDeclareFile(outputFeMacroDeclarePath);
863 0 : if(!outputFeMacroDeclareFile.is_open())
864 : {
865 0 : __SS__ << "\n\nERROR! Could not open FE Macro declaration output file at "
866 0 : << outputFeMacroDeclarePath << __E__;
867 0 : __SS_THROW__;
868 0 : }
869 0 : std::string outputFeMacroPath = exportPath + "/ROCTrackerInterface_" +
870 0 : prepend[i] + "_registerFEMacros.icc";
871 0 : std::ofstream outputFeMacroRegisterFile(outputFeMacroPath);
872 0 : if(!outputFeMacroRegisterFile.is_open())
873 : {
874 0 : __SS__
875 : << "\n\nERROR! Could not open FE Macro registration output file at "
876 0 : << outputFeMacroPath << __E__;
877 0 : __SS_THROW__;
878 0 : }
879 : std::string outputFeMacroDefinePath =
880 0 : exportPath + "/ROCTrackerInterface_" + prepend[i] + "_defineFEMacros.cc";
881 0 : std::ofstream outputFeMacroDefineFile(outputFeMacroDefinePath);
882 0 : if(!outputFeMacroDefineFile.is_open())
883 : {
884 0 : __SS__
885 : << "\n\nERROR! Could not open FE Macro registration output file at "
886 0 : << outputFeMacroDefinePath << __E__;
887 0 : __SS_THROW__;
888 0 : }
889 :
890 0 : std::stringstream headerInstructionsSs, headerIncludes;
891 :
892 : //////////////// source file header
893 0 : outputFile << "\n// clang-format off\n";
894 : outputFile << "\n//"
895 : "--------------------------------------------------------------"
896 0 : "---------------\n";
897 : headerInstructionsSs << "/// This file was auto-generated from " << importFile
898 0 : << "\n";
899 0 : headerInstructionsSs << "/// Do not modify this file directly.\n";
900 0 : headerInstructionsSs << "///\n";
901 : headerInstructionsSs << "/// To modify, edit " << importFile
902 0 : << " and re-run the import tool:\n";
903 0 : headerInstructionsSs << "///\n";
904 : headerInstructionsSs << "/// otsdaq_import_tracker_test_stand "
905 0 : << importPath << " " << exportPath << "\n";
906 0 : headerInstructionsSs << "///\n";
907 0 : outputFile << headerInstructionsSs.str();
908 : outputFile << "//"
909 : "--------------------------------------------------------------"
910 0 : "---------------\n";
911 :
912 : headerIncludes
913 : << "\n\n#include "
914 0 : "\"otsdaq-mu2e-tracker/FEInterfaces/ROCTrackerInterface.h\"\n\n";
915 0 : headerIncludes << "\n#include <TString.h> // includes ROOT's Form\n";
916 0 : headerIncludes << "\n#include <filesystem>\n";
917 :
918 0 : headerIncludes << "\n\nusing namespace ots;\n";
919 0 : headerIncludes << "\n#undef __MF_SUBJECT__\n";
920 0 : headerIncludes << "#define __MF_SUBJECT__ \"FE-ROCTrackerInterface\"\n";
921 :
922 0 : headerIncludes << "\n\n";
923 0 : outputFile << headerIncludes.str();
924 :
925 : //////////////// header file header
926 0 : outputHeaderFile << "\n// clang-format off\n";
927 : outputHeaderFile << "\n//"
928 : "--------------------------------------------------------"
929 0 : "----------------\n";
930 0 : outputHeaderFile << headerInstructionsSs.str();
931 : outputHeaderFile << "//"
932 : "--------------------------------------------------------"
933 0 : "----------------\n";
934 0 : outputHeaderFile << "\n\n";
935 :
936 : //////////////// FE macro declare file header
937 0 : outputFeMacroDeclareFile << "\n// clang-format off\n";
938 : outputFeMacroDeclareFile << "\n//"
939 : "------------------------------------------------"
940 0 : "------------------------\n";
941 0 : outputFeMacroDeclareFile << headerInstructionsSs.str();
942 : outputFeMacroDeclareFile << "//"
943 : "------------------------------------------------"
944 0 : "------------------------\n";
945 0 : outputFeMacroDeclareFile << "\n\n";
946 :
947 : //////////////// FE macro register source file header
948 0 : outputFeMacroRegisterFile << "\n// clang-format off\n";
949 : outputFeMacroRegisterFile << "\n//"
950 : "-----------------------------------------------"
951 0 : "-------------------------\n";
952 0 : outputFeMacroRegisterFile << headerInstructionsSs.str();
953 : outputFeMacroRegisterFile << "//"
954 : "-----------------------------------------------"
955 0 : "-------------------------\n";
956 0 : outputFeMacroRegisterFile << "\n\n";
957 :
958 : //////////////// FE macro deinition source file header
959 0 : outputFeMacroDefineFile << "\n// clang-format off\n";
960 : outputFeMacroDefineFile << "\n//"
961 : "-------------------------------------------------"
962 0 : "-----------------------\n";
963 0 : outputFeMacroDefineFile << headerInstructionsSs.str();
964 : outputFeMacroDefineFile << "//"
965 : "-------------------------------------------------"
966 0 : "-----------------------\n";
967 0 : outputFeMacroDefineFile << headerIncludes.str();
968 :
969 0 : const std::string functionNeedle = " DtcInterface::";
970 : //-----------------------------------------------------------------------------
971 : // search for each function definition
972 0 : size_t pos = 0;
973 : while(true)
974 : {
975 : // find the next function definition
976 0 : size_t funcPos = fileContents.find(" DtcInterface::", pos);
977 0 : pos = funcPos +
978 0 : functionNeedle.size(); // move past this point for next search
979 0 : if(funcPos == std::string::npos)
980 : {
981 0 : __COUTT__ << "No more functions found at " << funcPos << std::endl;
982 0 : break; // no more functions found
983 : }
984 :
985 0 : __COUT__ << "===========> Considering next DtcInterface:: pos = "
986 0 : << (fileContents.substr(funcPos, 50)) << __E__;
987 :
988 0 : size_t endFuncPos = fileContents.find(")", funcPos);
989 0 : if(endFuncPos == std::string::npos)
990 : {
991 0 : __COUTT__ << "Malformed function found at " << funcPos << std::endl;
992 0 : continue; // malformed function definition, so skip
993 0 : }
994 :
995 0 : __COUTV__(fileContents.substr(endFuncPos, 50));
996 :
997 : // find the opening brace of the function body
998 0 : size_t bracePos = fileContents.find("{", endFuncPos);
999 0 : if(bracePos == std::string::npos)
1000 : {
1001 0 : __COUTT__ << "Malformed function found at " << funcPos << std::endl;
1002 0 : continue; // malformed function definition, so skip
1003 0 : }
1004 :
1005 0 : __COUTV__(fileContents.substr(bracePos, 50));
1006 :
1007 : std::string functionHeader =
1008 0 : fileContents.substr(funcPos + functionNeedle.size(),
1009 0 : bracePos - (funcPos + functionNeedle.size()));
1010 :
1011 : // enforce that there are no special characters in function header between
1012 : // funcPos and bracePos
1013 0 : if(functionHeader.find("{") != std::string::npos ||
1014 0 : functionHeader.find("}") != std::string::npos ||
1015 0 : functionHeader.find("[") != std::string::npos ||
1016 0 : functionHeader.find("]") != std::string::npos ||
1017 0 : functionHeader.find(";") != std::string::npos)
1018 : {
1019 0 : __COUTT__ << "Malformed function found at " << funcPos << std::endl;
1020 0 : continue; // malformed function definition, so skip
1021 0 : }
1022 0 : __COUTV__(functionHeader);
1023 :
1024 : // find the matching closing brace
1025 0 : int braceCount = 1;
1026 0 : size_t endPos = bracePos + 1;
1027 0 : bool inComment = false;
1028 0 : bool inString = false;
1029 0 : while(endPos < fileContents.size() && braceCount > 0)
1030 : {
1031 0 : if(fileContents[endPos] == '{' && !inComment && !inString)
1032 : {
1033 0 : braceCount++;
1034 0 : __COUTT__ << "braceCount=" << braceCount
1035 0 : << fileContents.substr(endPos - 49, 50);
1036 : }
1037 0 : else if(fileContents[endPos] == '}' && !inComment && !inString)
1038 : {
1039 0 : braceCount--;
1040 0 : __COUTT__ << "braceCount=" << braceCount
1041 0 : << fileContents.substr(endPos - 49, 50);
1042 : }
1043 0 : else if(fileContents[endPos] == '/' &&
1044 0 : fileContents[endPos + 1] == '/')
1045 : {
1046 0 : inComment = true;
1047 0 : __COUTT__ << "inComment start"
1048 0 : << fileContents.substr(endPos - 49, 50);
1049 : }
1050 0 : else if(fileContents[endPos] == '\n' && inComment)
1051 : {
1052 0 : inComment = false;
1053 0 : __COUTT__ << "inComment end"
1054 0 : << fileContents.substr(endPos - 49, 50);
1055 : }
1056 0 : else if(fileContents[endPos] == '"' && !inComment)
1057 : {
1058 0 : inString = !inString; // toggle string state
1059 0 : __COUTT__ << "inString toggle to " << inString
1060 0 : << fileContents.substr(endPos - 49, 50);
1061 : }
1062 0 : endPos++;
1063 : }
1064 0 : __COUTV__(fileContents.substr(endPos - 50, 50));
1065 0 : if(braceCount != 0)
1066 : {
1067 0 : __COUTT__ << "Malformed function found at " << funcPos << " to "
1068 0 : << endPos << std::endl;
1069 0 : continue; // malformed function definition, so skip
1070 0 : }
1071 :
1072 : // extract the function definition
1073 : std::string functionDef =
1074 0 : fileContents.substr(bracePos, endPos - bracePos);
1075 :
1076 : // update position for next search
1077 0 : pos = endPos;
1078 :
1079 : // eliminate special functions that should not be imported
1080 0 : if(functionDef.find("fgInstance") != std::string::npos)
1081 : {
1082 0 : __COUTT__ << "Eliminated function def found at " << funcPos << " to "
1083 0 : << endPos << std::endl;
1084 0 : continue; // malformed function definition, so skip
1085 0 : }
1086 :
1087 : // prepend the specified string
1088 0 : __COUT__ << "Found: " + prepend[i] + "_" + functionHeader;
1089 :
1090 0 : size_t startFunc = fileContents.rfind('\n', funcPos);
1091 0 : if(startFunc == std::string::npos)
1092 : {
1093 0 : __COUTT__ << "Malformed function found at startFunc=" << startFunc
1094 0 : << " from " << funcPos << std::endl;
1095 0 : continue; // malformed function definition, so skip
1096 0 : }
1097 : std::string functionReturnVal =
1098 0 : fileContents.substr(startFunc + 1, funcPos - (startFunc + 1));
1099 0 : __COUTTV__(functionReturnVal);
1100 0 : functionReturnVal = StringMacros::trim(functionReturnVal);
1101 0 : __COUTV__(functionReturnVal);
1102 0 : if(functionReturnVal.size() == 0)
1103 : {
1104 0 : __COUTT__ << "Ignoring constructors/destructors functions."
1105 0 : << std::endl;
1106 0 : continue; // malformed function definition, so skip
1107 0 : }
1108 0 : __COUTTV__(startFunc);
1109 :
1110 : // accept as comment lines with "// "
1111 0 : --startFunc; // move before newline of function definition
1112 0 : std::string functionComment = "";
1113 : while(true)
1114 : {
1115 0 : size_t startComment1 = fileContents.rfind("//", startFunc);
1116 0 : size_t startComment2 = fileContents.rfind("\n", startFunc);
1117 0 : __COUTTV__(startComment1);
1118 0 : __COUTTV__(startComment2);
1119 :
1120 0 : if(startComment1 == std::string::npos ||
1121 0 : startComment1 < startComment2)
1122 : {
1123 0 : __COUTT__ << "No more comments found at " << startComment1 << " "
1124 0 : << fileContents.substr(startFunc - 48, 50) << std::endl;
1125 0 : break; // no more comments found
1126 : }
1127 0 : __COUTT__ << "Comment found at " << startComment1 << " "
1128 0 : << fileContents.substr(startFunc - 48, 50) << std::endl;
1129 :
1130 0 : if(fileContents[startComment1 + 2] == ' ') // is a comment line
1131 : {
1132 : // remove excess white space (from double comment)
1133 0 : while(fileContents[startFunc] == ' ')
1134 0 : --startFunc;
1135 :
1136 : functionComment =
1137 0 : "/" +
1138 0 : fileContents.substr(startComment1,
1139 0 : startFunc - startComment1 + 1) +
1140 0 : "\n" + functionComment;
1141 : }
1142 : // else //is a comment line to ignore
1143 :
1144 0 : startFunc = startComment1 - 2; // move before this comment line
1145 0 : } // end comment extraction loop
1146 :
1147 0 : __COUTTV__(functionComment);
1148 0 : __COUTTV__(functionDef);
1149 :
1150 : // output the function prototype to header file
1151 : std::string declaredFunctionHeader = getDeclaredFunctionHeader(
1152 0 : functionHeader, importPath + "/" + headerFilesToImport[i]);
1153 : outputHeaderFile
1154 0 : << modifySource(functionReturnVal) << " " << prepend[i] << "_"
1155 0 : << modifySource(declaredFunctionHeader, true /* isHeader */) << ";\n";
1156 :
1157 : // output the extracted function to source file
1158 : outputFile << "//"
1159 : "=========================================================="
1160 0 : "====================\n";
1161 0 : modifySource(functionHeader, true /* isHeader */);
1162 0 : outputFile << "///\t" << prepend[i] << "_"
1163 0 : << functionHeader.substr(0, functionHeader.find('('))
1164 0 : << "()\n";
1165 0 : outputFile << functionComment;
1166 0 : outputFile << headerInstructionsSs.str();
1167 : outputFile << functionReturnVal << " ROCTrackerInterface"
1168 0 : << "::" << prepend[i] << "_"
1169 0 : << functionHeader.substr(
1170 : 0,
1171 0 : functionHeader.size() -
1172 : 1 /* removing trailing white space */)
1173 0 : << "\n";
1174 0 : outputFile << modifySource(functionDef);
1175 0 : outputFile << " // end " << prepend[i] << "_"
1176 0 : << functionHeader.substr(0, functionHeader.find('('))
1177 0 : << "()\n\n";
1178 :
1179 : // if args are simple (int, string), then output the FE Macro declaration,
1180 : // registration, and definition
1181 0 : std::vector<std::string> argTypes, argNames, argDefaults, outputTypes,
1182 0 : outputNames;
1183 0 : __COUT__ << "Validating args for FE Macro... " << declaredFunctionHeader
1184 0 : << std::endl;
1185 0 : if(validateArgsForFEMacro(declaredFunctionHeader,
1186 : functionReturnVal,
1187 : argTypes,
1188 : argNames,
1189 : argDefaults,
1190 : outputTypes,
1191 : outputNames))
1192 : {
1193 0 : __COUT__ << "Valid FE Macro! " << prepend[i] << "_"
1194 0 : << functionHeader.substr(0, functionHeader.find('('))
1195 0 : << std::endl;
1196 : // --------------------------------------------
1197 : // FE Macro declaration ----------------
1198 : outputFeMacroDeclareFile
1199 0 : << "void FEMacro_" << prepend[i] << "_"
1200 0 : << functionHeader.substr(0, functionHeader.find('('))
1201 0 : << "(__ARGS__);\n";
1202 :
1203 : // --------------------------------------------
1204 : // FE Macro registration ----------------
1205 0 : outputFeMacroRegisterFile << "\n";
1206 : outputFeMacroRegisterFile
1207 0 : << " registerFEMacroFunction(\"" << prepend[i] << " "
1208 0 : << functionHeader.substr(0, functionHeader.find('(')) << "\",\n";
1209 : outputFeMacroRegisterFile
1210 : << " "
1211 0 : "static_cast<FEVInterface::frontEndMacroFunction_t>(\n";
1212 : outputFeMacroRegisterFile
1213 : << " "
1214 : "&ROCTrackerInterface::FEMacro_"
1215 0 : << prepend[i] << "_"
1216 0 : << functionHeader.substr(0, functionHeader.find('(')) << "),\n";
1217 : outputFeMacroRegisterFile
1218 0 : << " std::vector<std::string>{";
1219 0 : for(size_t o = 0, ocount = 0; o < argNames.size();
1220 : o++) // input args loop
1221 : {
1222 0 : if((argTypes[o].size() == 3 || argTypes[o].size() == 4) &&
1223 0 : argTypes[o].find("out") == 0)
1224 0 : continue; // skip output by reference/pointer args
1225 :
1226 0 : if(argNames[o] == "Link" || argNames[o] == "LinkMask")
1227 0 : continue; // skip link args (take from ROC member variable)
1228 :
1229 0 : if(ocount > 0)
1230 0 : outputFeMacroRegisterFile << ", ";
1231 0 : outputFeMacroRegisterFile << "\"" << argNames[o];
1232 :
1233 0 : if(argDefaults[o].size())
1234 0 : outputFeMacroRegisterFile << " (Default = " << argDefaults[o]
1235 0 : << ")";
1236 0 : outputFeMacroRegisterFile << "\"";
1237 0 : ++ocount;
1238 : } // end input args loop
1239 0 : outputFeMacroRegisterFile << "}, // inputs parameters\n";
1240 : outputFeMacroRegisterFile
1241 0 : << " std::vector<std::string>{";
1242 0 : for(size_t o = 0, ocount = 0; o < outputNames.size();
1243 : o++) // output args loop
1244 : {
1245 0 : if(outputTypes[o] == "void")
1246 0 : continue; // no output to declare
1247 :
1248 0 : if(ocount > 0)
1249 0 : outputFeMacroRegisterFile << ", ";
1250 0 : outputFeMacroRegisterFile << "\"" << outputNames[o] << "\"";
1251 0 : ++ocount;
1252 : } // end output args loop
1253 0 : outputFeMacroRegisterFile << "}, // output parameters\n";
1254 : outputFeMacroRegisterFile << " 1); // "
1255 0 : "requiredUserPermissions\n";
1256 :
1257 : // --------------------------------------------
1258 : // FE Macro definition ----------------
1259 0 : outputFeMacroDefineFile << "\n";
1260 : outputFeMacroDefineFile << "//"
1261 : "========================================="
1262 0 : "=====================================\n";
1263 : outputFeMacroDefineFile
1264 0 : << "/// FE Macro to call " << prepend[i] << "_"
1265 0 : << functionHeader.substr(0, functionHeader.find('(')) << "()\n";
1266 0 : outputFeMacroDefineFile << "///\n";
1267 0 : outputFeMacroDefineFile << headerInstructionsSs.str();
1268 : outputFeMacroDefineFile
1269 0 : << "void ROCTrackerInterface::FEMacro_" << prepend[i] << "_"
1270 0 : << functionHeader.substr(0, functionHeader.find('('))
1271 0 : << "(__ARGS__)";
1272 : outputFeMacroDefineFile <<
1273 0 : R"(
1274 : {
1275 : __FE_COUT__ << "# of input args = " << argsIn.size() << __E__;
1276 : __FE_COUT__ << "# of output args = " << argsOut.size() << __E__;
1277 : for(auto& argIn : argsIn)
1278 : __FE_COUT__ << argIn.first << ": " << argIn.second << __E__;
1279 :
1280 : )";
1281 :
1282 0 : for(size_t o = 0; o < argNames.size(); o++) // declare input args
1283 : {
1284 0 : if((argTypes[o].size() == 3 || argTypes[o].size() == 4) &&
1285 0 : argTypes[o].find("out") == 0)
1286 0 : continue; // skip output by reference/pointer args
1287 :
1288 0 : if(argTypes[o].find('&') !=
1289 : std::string::npos) // remove the & from output by reference
1290 : // args
1291 : outputFeMacroDefineFile
1292 0 : << "\t" << argTypes[o].substr(0, argTypes[o].size() - 1)
1293 0 : << " " << argNames[o] << " = ";
1294 : else
1295 0 : outputFeMacroDefineFile << "\t" << argTypes[o] << " "
1296 0 : << argNames[o] << " = ";
1297 :
1298 0 : if(argNames[o] ==
1299 : "Link") // for link args, take from ROC member variable
1300 : {
1301 : outputFeMacroDefineFile
1302 0 : << "ROCCoreVInterface::getLinkID();\n";
1303 : }
1304 0 : else if(argNames[o] == "LinkMask") // for link mask args, take
1305 : // from ROC member variable
1306 : {
1307 : // nibble based link mask
1308 : outputFeMacroDefineFile
1309 0 : << "1 << (ROCCoreVInterface::getLinkID() * 4);\n";
1310 : }
1311 : else // normal input arg
1312 : {
1313 : outputFeMacroDefineFile << "__GET_ARG_IN__"
1314 0 : << "(\"" << argNames[o];
1315 :
1316 0 : if(argDefaults[o].size())
1317 : outputFeMacroDefineFile
1318 0 : << " (Default = " << argDefaults[o] << ")";
1319 :
1320 0 : if(argTypes[o].find('&') !=
1321 : std::string::npos) // remove the & from output by
1322 : // reference args
1323 : outputFeMacroDefineFile
1324 : << "\""
1325 : << ", "
1326 0 : << argTypes[o].substr(0, argTypes[o].size() - 1);
1327 : else
1328 : outputFeMacroDefineFile << "\""
1329 0 : << ", " << argTypes[o];
1330 :
1331 0 : if(argDefaults[o].size())
1332 0 : outputFeMacroDefineFile << ", " << argDefaults[o];
1333 :
1334 0 : outputFeMacroDefineFile << ");\n";
1335 : }
1336 : } // end declare input args loop
1337 :
1338 0 : outputFeMacroDefineFile << "\n";
1339 0 : for(size_t o = 0; o < outputNames.size(); o++) // declare output args
1340 : {
1341 0 : if(outputTypes[o] == "void")
1342 0 : continue; // no output to declare
1343 :
1344 0 : if(outputTypes[o].find('&') !=
1345 : std::string::npos) // remove the & from output by reference
1346 : // args
1347 : {
1348 0 : if(outputTypes[o] ==
1349 : "std::ostream&") // special case for ostream
1350 : outputFeMacroDefineFile << "\t"
1351 : << "std::stringstream"
1352 0 : << " " << outputNames[o] << ";\n";
1353 : else
1354 : outputFeMacroDefineFile
1355 : << "\t"
1356 0 : << outputTypes[o].substr(0, outputTypes[o].size() - 1)
1357 0 : << " " << outputNames[o] << ";\n";
1358 : }
1359 0 : else if(outputTypes[o].find('*') !=
1360 : std::string::npos) // remove the * from output by
1361 : // reference args
1362 : outputFeMacroDefineFile
1363 : << "\t"
1364 0 : << outputTypes[o].substr(0, outputTypes[o].size() - 1)
1365 0 : << " " << outputNames[o] << ";\n";
1366 : else
1367 0 : outputFeMacroDefineFile << "\t" << outputTypes[o] << " "
1368 0 : << outputNames[o] << ";\n";
1369 : } // end declare output args loop
1370 :
1371 0 : outputFeMacroDefineFile << "\n";
1372 0 : if(outputNames.size() && functionReturnVal != "void")
1373 0 : outputFeMacroDefineFile << "\t" << outputNames[0] << " =\n\t";
1374 : outputFeMacroDefineFile
1375 : << "\t"
1376 : << "trackerDTC_->"
1377 : // << "\t" << prepend[i] << "_"
1378 0 : << functionHeader.substr(0, functionHeader.find('(')) << "(";
1379 :
1380 0 : for(size_t o = 0; o < argNames.size(); o++)
1381 : {
1382 0 : if(o > 0)
1383 0 : outputFeMacroDefineFile << ", ";
1384 0 : if(argTypes[o] ==
1385 : "out*") // needed to pass as pointer for output result
1386 0 : outputFeMacroDefineFile << "&";
1387 0 : outputFeMacroDefineFile << argNames[o];
1388 : }
1389 0 : outputFeMacroDefineFile << ");\n\n";
1390 :
1391 0 : for(size_t o = 0; o < outputNames.size(); o++) // set output args
1392 : {
1393 0 : if(outputTypes[o] == "void")
1394 0 : continue; // no output to set
1395 :
1396 : // handle special output types
1397 0 : if(outputTypes[o].find("std::vector") != std::string::npos)
1398 : outputFeMacroDefineFile
1399 0 : << "\t__SET_ARG_OUT__(\"" << outputNames[o]
1400 0 : << "\", StringMacros::vectorToString(" << outputNames[o]
1401 0 : << "));\n";
1402 0 : else if(outputTypes[o] ==
1403 : "std::ostream&") // special case for ostream
1404 : {
1405 : outputFeMacroDefineFile << "\t__COUT_MULTI__(2, "
1406 0 : << outputNames[o] << ".str());\n";
1407 : outputFeMacroDefineFile << "\t__SET_ARG_OUT__(\""
1408 0 : << outputNames[o] << "\", "
1409 0 : << outputNames[o] << ".str());\n";
1410 : }
1411 : else // normal output type
1412 : outputFeMacroDefineFile << "\t__SET_ARG_OUT__(\""
1413 0 : << outputNames[o] << "\", "
1414 0 : << outputNames[o] << ");\n";
1415 : } // end set output args loop
1416 0 : outputFeMacroDefineFile << "\n";
1417 :
1418 : outputFeMacroDefineFile
1419 0 : << "} // end FEMacro_" << prepend[i] << "_"
1420 0 : << functionHeader.substr(0, functionHeader.find('(')) << "()\n";
1421 : } // end outputing FE Macro definition, registration, declaration
1422 :
1423 : // flush output files so progress can be debugged if needed
1424 0 : outputFile.flush();
1425 0 : outputHeaderFile.flush();
1426 0 : outputFeMacroDeclareFile.flush();
1427 0 : outputFeMacroRegisterFile.flush();
1428 0 : outputFeMacroDefineFile.flush();
1429 :
1430 : // break; //for debugging, only do one function per file
1431 0 : } // end main function search loop
1432 :
1433 0 : outputFile << "// clang-format on\n";
1434 0 : outputHeaderFile << "// clang-format on\n";
1435 0 : outputFeMacroDeclareFile << "// clang-format on\n";
1436 0 : outputFeMacroRegisterFile << "// clang-format on\n";
1437 0 : outputFeMacroDefineFile << "// clang-format on\n";
1438 :
1439 0 : outputFile.close();
1440 0 : outputHeaderFile.close();
1441 0 : outputFeMacroDeclareFile.close();
1442 0 : outputFeMacroRegisterFile.close();
1443 0 : outputFeMacroDefineFile.close();
1444 :
1445 0 : __COUT_INFO__ << "Successfully wrote output file at " << outputFilePath
1446 0 : << std::endl;
1447 0 : __COUT_INFO__ << "Successfully wrote header file at " << outputHeaderPath
1448 0 : << std::endl;
1449 0 : __COUT_INFO__ << "Successfully wrote FE Macro declaration file at "
1450 0 : << outputFeMacroDeclarePath << std::endl;
1451 0 : __COUT_INFO__ << "Successfully wrote FE Macro registration file at "
1452 0 : << outputFeMacroPath << std::endl;
1453 0 : __COUT_INFO__ << "Successfully wrote FE Macro define file at "
1454 0 : << outputFeMacroDefinePath << std::endl;
1455 0 : }
1456 0 : catch(const std::runtime_error& e)
1457 : {
1458 0 : importErrors.push_back(
1459 0 : std::make_pair(importFile,
1460 0 : prepend[i] + " " + importFile +
1461 0 : std::string(" std::runtime_error: ") + e.what()));
1462 0 : }
1463 0 : catch(const std::exception& e)
1464 : {
1465 0 : importErrors.push_back(std::make_pair(importFile,
1466 0 : prepend[i] + " " + importFile +
1467 0 : std::string(" std::exception: ") +
1468 0 : e.what()));
1469 0 : }
1470 0 : catch(...)
1471 : {
1472 0 : importErrors.push_back(std::make_pair(
1473 : importFile,
1474 0 : prepend[i] + " " + importFile + " Unknown exception occurred."));
1475 0 : }
1476 0 : } // end main import loop
1477 :
1478 0 : if(importErrors.size())
1479 : {
1480 0 : __COUT_ERR__ << "There were " << importErrors.size()
1481 0 : << " errors found while importing. See below:\n"
1482 0 : << std::endl;
1483 0 : for(auto& importErr : importErrors)
1484 0 : __COUT_ERR__ << "\t" << importErr.first << ": " << importErr.second
1485 0 : << std::endl;
1486 0 : __COUT_ERR__ << "End of errors.\n\n" << std::endl;
1487 : }
1488 : else
1489 0 : __COUT_INFO__ << "There were NO ERRORS found while loading and exporting groups."
1490 0 : << __E__;
1491 0 : std::cout << "Import of Tracker Test Stand complete!\n";
1492 :
1493 0 : } // end ImportTrackerTestStand()
1494 :
1495 : //==============================================================================
1496 0 : int main(int argc, char* argv[])
1497 : {
1498 : //==============================================================================
1499 : // Define environment variables
1500 : // Note: normally these environment variables are set by ots script
1501 :
1502 0 : test::util::check_and_make_envs();
1503 :
1504 : ////////////////////////////////////////////////////
1505 :
1506 0 : INIT_MF("ImportTrackerTestStand");
1507 0 : ImportTrackerTestStand(argc, argv);
1508 0 : return 0;
1509 : } // end main()
1510 : // BOOST_AUTO_TEST_SUITE_END()
|