/// Load a db file multiple times substituting a specified macro according to a number range. /// /// The \a dbFile and \a macros arguments are like the normal dbLoadRecords() however /// it is possible to embed a macro within these whose value follows the range \a start to \a stop. /// You can either load the same \a dbFile multiple times with different macros, or even load /// different database files by using \a loopVar as part of the filename. If you want to use a list /// of (non-numeric) substitutions rather than an integer range see dbLoadRecordsList() /// /// The name of the macro to be used for substitution is contained in \a loopVar and needs to be /// reference in an \\ escaped way to make sure EPICS does not try to substitute it too soon. /// as well as the \a macros the \a dbFile is also passed the \a loopVar macro value /// @code /// dbLoadRecordsLoop("file\$(I).db", "P=1,Q=Hello\$(I)", "I", 1, 4) /// @endcode /// /// @param[in] dbFile @copydoc dbLoadRecordsLoopInitArg0 /// @param[in] macros @copydoc dbLoadRecordsLoopInitArg1 /// @param[in] loopVar @copydoc dbLoadRecordsLoopInitArg2 /// @param[in] start @copydoc dbLoadRecordsLoopInitArg3 /// @param[in] stop @copydoc dbLoadRecordsLoopInitArg4 /// @param[in] step @copydoc dbLoadRecordsLoopInitArg5 epicsShareFunc void dbLoadRecordsLoop(const char* dbFile, const char* macros, const char* loopVar, int start, int stop, int step) { char loopVal[32]; if (loopVar == NULL) { dbLoadRecords(dbFile, macros); return; } if (step <= 0) { step = 1; } std::string macros_s, dbFile_s; subMacros(macros_s, macros, loopVar); subMacros(dbFile_s, dbFile, loopVar); MAC_HANDLE* mh = NULL; char macros_exp[1024], dbFile_exp[1024]; macCreateHandle(&mh, NULL); loadMacEnviron(mh); for(int i = start; i <= stop; i += step) { macPushScope(mh); epicsSnprintf(loopVal, sizeof(loopVal), "%d", i); macPutValue(mh, loopVar, loopVal); macExpandString(mh, macros_s.c_str(), macros_exp, sizeof(macros_exp)); macExpandString(mh, dbFile_s.c_str(), dbFile_exp, sizeof(dbFile_exp)); std::ostringstream new_macros; new_macros << macros_exp << (strlen(macros_exp) > 0 ? "," : "") << loopVar << "=" << i; std::cout << "--> (" << i << ") dbLoadRecords(\"" << dbFile_exp << "\",\"" << new_macros.str() << "\")" << std::endl; dbLoadRecords(dbFile_exp, new_macros.str().c_str()); macPopScope(mh); } macDeleteHandle(mh); }
/// Load a db file multiple times according to a list of items separated by known separator(s). /// /// The \a dbFile and \a macros arguments are like the normal dbLoadRecords() however /// it is possible to embed a macro within these whose value takes a value from the \a list. /// You can either load the same \a dbFile multiple times with different macros, or even load /// different database files by using \a loopVar as part of the filename. If you want to use a /// pure numeric range see dbLoadRecordsLoop() /// /// The name of the macro to be used for substitution is contained in \a loopVar and needs to be /// reference in an \\ escaped way to make sure EPICS does not try to substitute it too soon. /// as well as the \a macros the \a dbFile is also passed the \a loopVar macro value /// @code /// dbLoadRecordsList("file\$(S).db", "P=1,Q=Hello\$(S)", "S", "A;B;C", ";") /// @endcode /// /// @param[in] dbFile @copydoc dbLoadRecordsListInitArg0 /// @param[in] macros @copydoc dbLoadRecordsListInitArg1 /// @param[in] loopVar @copydoc dbLoadRecordsListInitArg2 /// @param[in] list @copydoc dbLoadRecordsListInitArg3 /// @param[in] sep @copydoc dbLoadRecordsListInitArg4 epicsShareFunc void dbLoadRecordsList(const char* dbFile, const char* macros, const char* loopVar, const char* list, const char* sep) { static const char* default_sep = ";"; if (loopVar == NULL || list == NULL) { dbLoadRecords(dbFile, macros); return; } if (sep == NULL) { sep = default_sep; } std::string macros_s, dbFile_s; subMacros(macros_s, macros, loopVar); subMacros(dbFile_s, dbFile, loopVar); MAC_HANDLE* mh = NULL; char macros_exp[1024], dbFile_exp[1024]; macCreateHandle(&mh, NULL); loadMacEnviron(mh); char* saveptr = NULL; char* list_tmp = strdup(list); char* list_item = epicsStrtok_r(list_tmp, sep, &saveptr); while(list_item != NULL) { macPushScope(mh); macPutValue(mh, loopVar, list_item); macExpandString(mh, macros_s.c_str(), macros_exp, sizeof(macros_exp)); macExpandString(mh, dbFile_s.c_str(), dbFile_exp, sizeof(dbFile_exp)); std::ostringstream new_macros; new_macros << macros_exp << (strlen(macros_exp) > 0 ? "," : "") << loopVar << "=" << list_item; std::cout << "--> (" << list_item << ") dbLoadRecords(\"" << dbFile_exp << "\",\"" << new_macros.str() << "\")" << std::endl; dbLoadRecords(dbFile_exp, new_macros.str().c_str()); list_item = epicsStrtok_r(NULL, sep, &saveptr); macPopScope(mh); } free(list_tmp); macDeleteHandle(mh); }
int main(int argc, char *const argv[]) { puts(""); argF = 0; // -f argument: file - use file as a makefile argK = 0; // -k argument: keep going - Continue as much as possible after error argN = 0; // -n argument: Just print - print the commands that would be executed, don't execute argQ = 0; // -q argument: question - don't run commands hasChanged = 0; bool hasTarget = 0; // whether or not a target is specified from command line char *makeFile; // filename for the makefile being used. char *target; // target to be used FILE *myFile; // file to be used for reading int c; // used for getopt loop while((c = getopt(argc, argv, "f:knq")) != -1) // Collect command arguments { if(c == 'k') argK = 1; // set K if(c == 'f' && argF == 0) // set F (only if it has not been set before) { argF = 1; makeFile = (char*)calloc(1, strlen(optarg) + 1); // extract filename strcpy(makeFile, optarg); } if(c == 'n') argN = 1; // set N if(c == 'q') argQ = 1; // set Q } if(!argF) { struct stat fileBuf; if(stat("GNUmakefile", &fileBuf) == 0) makeFile = "GNUmakefile"; else if(stat("makefile", &fileBuf) == 0) makeFile = "makefile"; else if(stat("Makefile", &fileBuf) == 0) makeFile = "Makefile"; else { printf("Could not find a default makefile. Program terminating...\n"); exit(0); } } if(argc > optind) // if there are still arguments after the command options, { // extract the target command from the argument list hasTarget = 1; target = calloc(1, strlen(argv[optind]) + 1); strcpy(target, argv[optind]); originalTarget = target; } myFile = fopen(makeFile, "r"); char line[MACROSIZE]; char *makeString[MACROSIZE]; int counter = 0; if( myFile != NULL) { while(fgets (line, sizeof line, myFile) != NULL) { makeString[counter] = calloc(1, strlen(line) + 1); strcpy(makeString[counter], line); // puts(makeString[counter]); counter ++; } fclose(myFile); } macI *firstMacro = calloc(1, sizeof(macI)); firstMacro = createList(firstMacro, makeString, counter); for(int i = 0; i < counter; i++) { char *temp = subMacros(makeString[i], firstMacro); makeString[i] = realloc(makeString[i], strlen(temp) + 1); strcpy(makeString[i], temp); RemoveNewLines(makeString[i]); makeString[i] = RemoveStartSpaces(makeString[i]); } tItem *firstTarget = calloc(1, sizeof(tItem)); firstTarget = insertTarget(firstTarget, FIRSTTARGET); switch(evaluateTarget(makeString, target, counter, hasTarget, firstTarget)) { case 3: // puts("1"); return 1; break; case 4: // puts("0"); return 0; break; default: break; } // ****************************************** FREE MEMORY ************************************* // ****************************************** FREE MEMORY ************************************* // ****************************************** FREE MEMORY ************************************* if(hasChanged == 0) printf("mymake: `%s' is up to date.\n", originalTarget); if(argF) free(makeFile); if(hasTarget) free(target); for(int i = 0; i < counter; i ++) free(makeString[counter]); freeTargets(firstTarget); freeMacros(firstMacro); }