-
Notifications
You must be signed in to change notification settings - Fork 0
Modify filecontentsserver to take an output file #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
20dd9f6
51a5608
656ecfc
a30afdb
ac52cf5
fb5eddf
56a6f26
0ce321e
d2b0423
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,14 +5,13 @@ | |
| #include <math.h> | ||
| #include <exception> | ||
| #include <iostream> | ||
| #include <format> | ||
| #include <map> | ||
| #include <list> | ||
| #include <vector> | ||
| #include <iomanip> | ||
| #include <fstream> | ||
| #include <sys/timeb.h> | ||
| #include <boost/algorithm/string.hpp> | ||
| #include <boost/algorithm/string/join.hpp> | ||
| #include <sstream> | ||
|
|
||
| #include <epicsTypes.h> | ||
|
|
@@ -40,9 +39,9 @@ | |
|
|
||
| static const char *driverName = "FileContentsServerDriver"; | ||
|
|
||
| FileContentsServerDriver::FileContentsServerDriver(const char *portName, const char *fileDir) | ||
| FileContentsServerDriver::FileContentsServerDriver(const char *portName, const char *fileDir, const char *inputFile, const char *outputFile) | ||
| : asynPortDriver(portName, | ||
| 0, /* maxAddr */ | ||
| 0, /* maxAddr */ | ||
| asynInt32Mask | asynInt32ArrayMask | asynFloat64Mask | asynFloat64ArrayMask | asynOctetMask | asynDrvUserMask, /* Interface mask */ | ||
| asynInt32Mask | asynInt32ArrayMask | asynFloat64Mask | asynFloat64ArrayMask | asynOctetMask, /* Interrupt mask */ | ||
| ASYN_CANBLOCK, /* asynFlags. This driver can block but it is not multi-device */ | ||
|
|
@@ -52,30 +51,85 @@ FileContentsServerDriver::FileContentsServerDriver(const char *portName, const c | |
| m_fileDir(fileDir) | ||
| { | ||
| const char *functionName = "FileContentsServerDriver"; | ||
| createParam(P_fileNameString, asynParamOctet, &P_fileName); | ||
|
|
||
| createParam(P_inputFileNameString, asynParamOctet, &P_inputFileName); | ||
| createParam(P_outputFileNameString, asynParamOctet, &P_outputFileName); | ||
| createParam(P_fileContentsString, asynParamOctet, &P_fileContents); | ||
| createParam(P_saveFileString, asynParamInt32, &P_saveFile); | ||
| createParam(P_resetString, asynParamInt32, &P_reset); | ||
| createParam(P_fileDirString, asynParamOctet, &P_fileDir); | ||
| createParam(P_logString, asynParamOctet, &P_log); | ||
| createParam(P_newFileWarningString, asynParamInt32, &P_newFileWarning); | ||
| createParam(P_unsavedChangesString, asynParamInt32, &P_unsavedChanges); | ||
|
|
||
| setStringParam(P_fileDir, fileDir); | ||
| setStringParam(P_inputFileName, inputFile); | ||
|
|
||
| // Read the original contents in first. | ||
| readFile(); | ||
|
|
||
| if (outputFile && *outputFile) | ||
| { | ||
| setStringParam(P_outputFileName, outputFile); | ||
| // Save the file so that the output file has the contents of the input file initially. | ||
| saveFile(); | ||
| } | ||
| else | ||
| { | ||
| // If the output file is not specified, default to saving output to the input file. | ||
| setStringParam(P_outputFileName, inputFile); | ||
| } | ||
|
|
||
| const int defaultSaveFile = 0; | ||
| setIntegerParam(P_saveFile, defaultSaveFile); | ||
| const int defaultReset = 0; | ||
| setIntegerParam(P_reset, defaultReset); | ||
| const int defaultNewFileWarning = 0; | ||
| setIntegerParam(P_newFileWarning, defaultNewFileWarning); | ||
| const int defaultUnsavedChanges = 0; | ||
| setIntegerParam(P_unsavedChanges, defaultUnsavedChanges); | ||
| setStringParam(P_fileContents, ""); | ||
| setStringParam(P_log, ""); | ||
| logMessage("Editor initialized"); | ||
| callParamCallbacks(); | ||
| } | ||
|
|
||
| asynStatus FileContentsServerDriver::saveFile() | ||
| { | ||
| logMessage("Triggering save"); | ||
|
|
||
| std::string buffer; | ||
|
|
||
| // Get the value of the parameter we just set | ||
| getStringParam(P_fileContents, buffer); | ||
|
|
||
| std::string fileName; | ||
| getStringParam(P_outputFileName, fileName); | ||
| // join the file name with the file directory | ||
| std::string fullFileName = m_fileDir + "/" + fileName; | ||
| // Write the contents of buffer to a file | ||
| try | ||
| { | ||
| std::ofstream outfile(fullFileName, std::ios::trunc | std::ios::binary); // Open in write mode | ||
| if (outfile.is_open()) | ||
| { | ||
| outfile << buffer; | ||
| outfile.close(); | ||
| logMessage("File saved successfully"); | ||
| setIntegerParam(P_saveFile, 0); | ||
| setIntegerParam(P_unsavedChanges, 0); | ||
| } | ||
| else | ||
| { | ||
| logMessage(std::format("Failed to open file ({}) for writing", fullFileName)); | ||
| return asynError; | ||
| } | ||
| } | ||
| catch (const std::exception &e) | ||
| { | ||
| logMessage(e.what()); | ||
| return asynError; | ||
| } | ||
| callParamCallbacks(); | ||
| return asynSuccess; | ||
| } | ||
|
|
||
| // Override the method to handle writes to parameters | ||
| asynStatus FileContentsServerDriver::writeInt32(asynUser *pasynUser, epicsInt32 value) | ||
| { | ||
|
|
@@ -85,55 +139,17 @@ asynStatus FileContentsServerDriver::writeInt32(asynUser *pasynUser, epicsInt32 | |
| { | ||
| if (value == 1 && hasChanged == 1) | ||
| { | ||
| std::cout << "Triggering save" << std::endl; | ||
| std::cout << "Value received by asyn: " << value << std::endl; | ||
|
|
||
| char buffer[5000]; // Assuming the response will fit within 256 characters | ||
|
|
||
| // Get the value of the parameter we just set | ||
| getStringParam(P_fileContents, sizeof(buffer), buffer); | ||
|
|
||
| char fileName[512]; | ||
| getStringParam(P_fileName, sizeof(fileName), fileName); | ||
| // join the file name with the file directory | ||
| std::string m_fullFileName = m_fileDir + "/" + fileName; | ||
| // Write the contents of buffer to a file | ||
| try | ||
| { | ||
| std::ofstream outfile(m_fullFileName, std::ios::trunc | std::ios::binary); // Open in write mode | ||
| if (outfile.is_open()) | ||
| { | ||
| outfile << buffer; | ||
| outfile.close(); | ||
| std::cout << "Contents written to file successfully." << std::endl; | ||
| logMessage("File saved successfully"); | ||
| setIntegerParam(P_saveFile, 0); | ||
| setIntegerParam(P_newFileWarning, 0); | ||
| setIntegerParam(P_unsavedChanges, 0); | ||
| } | ||
| else | ||
| { | ||
| std::cerr << "Failed to open file for writing." << std::endl; | ||
| logMessage("Failed to open file for writing"); | ||
| return asynError; | ||
| } | ||
| } | ||
| catch (const std::exception &e) | ||
| { | ||
| std::cerr << "Exception caught: " << e.what() << std::endl; | ||
| logMessage(e.what()); | ||
| return asynError; | ||
| } | ||
| callParamCallbacks(); | ||
| return saveFile(); | ||
| } | ||
| return asynSuccess; | ||
| } | ||
| else if (pasynUser->reason == P_reset) | ||
| { | ||
| if (value == 1) | ||
| { | ||
| std::cout << "Resetting" << std::endl; | ||
| logMessage("Reloading from disk"); | ||
| setStringParam(P_fileContents, m_original_lines_array); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't actually reloading from disk, it is resetting to what was there the first time it loaded from disk. Is that what the users would expect?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think so but can force a read - in reality the master copies never change |
||
| saveFile(); | ||
| logMessage("Reset successful."); | ||
| setIntegerParam(P_reset, 0); | ||
| setIntegerParam(P_unsavedChanges, 0); | ||
|
|
@@ -147,7 +163,7 @@ asynStatus FileContentsServerDriver::writeInt32(asynUser *pasynUser, epicsInt32 | |
| } | ||
| } | ||
|
|
||
| void FileContentsServerDriver::logMessage(const std::string& message) | ||
| void FileContentsServerDriver::logMessage(const std::string &message) | ||
| { | ||
| // add the time to the front of the log message | ||
| // current time | ||
|
|
@@ -162,38 +178,38 @@ void FileContentsServerDriver::logMessage(const std::string& message) | |
| // Create the log message | ||
| std::string log_message = std::string(time_str) + ": " + message; | ||
|
|
||
| std::cout << log_message << std::endl; | ||
| setStringParam(P_log, log_message); | ||
| callParamCallbacks(); | ||
| } | ||
|
|
||
| void FileContentsServerDriver::readFile() | ||
| { | ||
| std::cout << "Calling readFile" << std::endl; | ||
| std::fstream f; | ||
| char fileName[256]; | ||
| getStringParam(P_fileName, sizeof(fileName), fileName); | ||
| std::string m_fullFileName = m_fileDir + "/" + fileName; | ||
| std::cout << "FileContentsServerDriver: Reading file " << m_fullFileName << std::endl; | ||
| std::ifstream f; | ||
| std::string fileName; | ||
| getStringParam(P_inputFileName, fileName); | ||
| std::string fullFileName = m_fileDir + "/" + fileName; | ||
|
|
||
| logMessage(std::format("Reading file {}", fullFileName)); | ||
| try | ||
| { | ||
| f.open(m_fullFileName, std::ios::in); | ||
| f.open(fullFileName, std::ios::binary); | ||
| if (!f.is_open()) | ||
| { | ||
| m_original_lines_array = ""; | ||
| setStringParam(P_fileContents, ""); | ||
| if (errno == ENOENT) // File not found | ||
| { | ||
| std::cout << "File not found: " + m_fullFileName << std::endl; | ||
| setIntegerParam(P_newFileWarning, 1); | ||
| throw std::runtime_error("File not found"); | ||
| logMessage(std::format("File not found: {}", fullFileName)); | ||
| throw std::runtime_error("File not found"); | ||
| } | ||
| else // Other errors, e.g., permission denied | ||
| { | ||
| std::cerr << "Unable to open file: " + m_fullFileName << std::endl; | ||
| throw std::runtime_error(std::string("Unable to open file: ") + std::string(strerror(errno))); | ||
| logMessage(std::format("Unable to open file: {}, error {}", fullFileName, std::string(strerror(errno)))); | ||
| throw std::runtime_error(std::string("Unable to open file: ") + std::string(strerror(errno))); | ||
| } | ||
| } | ||
| setIntegerParam(P_newFileWarning, 0); | ||
| int i = 0; | ||
|
|
||
| std::stringstream buffer; | ||
|
|
@@ -209,7 +225,7 @@ void FileContentsServerDriver::readFile() | |
| catch (const std::exception &e) | ||
| { | ||
| std::cerr << "Exception caught: " << e.what() << std::endl; | ||
| logMessage(e.what()); | ||
| logMessage(e.what()); | ||
| } | ||
|
|
||
| callParamCallbacks(); | ||
|
|
@@ -235,12 +251,6 @@ asynStatus FileContentsServerDriver::writeOctet(asynUser *pasynUser, const char | |
| setIntegerParam(P_unsavedChanges, 0); | ||
| } | ||
| } | ||
| else if (function == P_fileName) | ||
| { | ||
| std::cout << "Setting file name to " << value << std::endl; | ||
| setStringParam(P_fileName, value); | ||
| readFile(); | ||
| } | ||
| else | ||
| { | ||
| return asynPortDriver::writeOctet(pasynUser, value, maxChars, nActual); | ||
|
|
@@ -259,11 +269,11 @@ extern "C" | |
|
|
||
| /// \param[in] portName @copydoc initArg0 | ||
| /// \param[in] fileDir @copydoc initArg1 | ||
| int FileContentsServerConfigure(const char *portName, const char *fileDir) | ||
| int FileContentsServerConfigure(const char *portName, const char *fileDir, const char *inputFile, const char *outputFile) | ||
| { | ||
| try | ||
| { | ||
| FileContentsServerDriver *driver = new FileContentsServerDriver(portName, fileDir); | ||
| FileContentsServerDriver *driver = new FileContentsServerDriver(portName, fileDir, inputFile, outputFile); | ||
| if (driver == NULL) | ||
| { | ||
| errlogSevPrintf(errlogMajor, "FileContentsServerConfigure failed (NULL)\n"); | ||
|
|
@@ -283,17 +293,21 @@ extern "C" | |
|
|
||
| // EPICS iocsh shell commands | ||
|
|
||
| static const iocshArg initArg0 = {"portName", iocshArgString}; ///< The name of the asyn driver port we will create | ||
| static const iocshArg initArg1 = {"fileDir", iocshArgString}; ///< file name | ||
| static const iocshArg initArg0 = {"portName", iocshArgString}; ///< The name of the asyn driver port we will create | ||
| static const iocshArg initArg1 = {"fileDir", iocshArgString}; ///< The directory to open/save files into | ||
| static const iocshArg initArg2 = {"inputFile", iocshArgString}; ///< input file name to read and initially serve contents of | ||
| static const iocshArg initArg3 = {"outputFile", iocshArgString}; ///< file name to save output to when a user hits save. If not set this defaults to inputFile. | ||
|
|
||
| static const iocshArg *const initArgs[] = {&initArg0, | ||
| &initArg1}; | ||
| &initArg1, | ||
| &initArg2, | ||
| &initArg3}; | ||
|
|
||
| static const iocshFuncDef initFuncDef = {"FileContentsServerConfigure", sizeof(initArgs) / sizeof(iocshArg *), initArgs}; | ||
|
|
||
| static void initCallFunc(const iocshArgBuf *args) | ||
| { | ||
| FileContentsServerConfigure(args[0].sval, args[1].sval); | ||
| FileContentsServerConfigure(args[0].sval, args[1].sval, args[2].sval, args[3].sval); | ||
| } | ||
|
|
||
| static void FileContentsServerRegister(void) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.