/******************************************************************** * Extract child program (master or slave) name and and * arguments from options. sSide should be 'master' or * 'slave', program and arguments are returned. * * Checks the "combo" options first (e.g. "master"). Then, if * these are not present, look for master-program and * master-arguments. *******************************************************************/ int GetChild(Feedback &fb, const std::string &sSide, std::string &sProgram, std::string &sArguments) { if (Options::Instance().IsUserSet(sSide)) { if (Options::Instance().Option(sSide, sProgram)) return fb.Error(E_CHILD_SETUP) << ": Unable to get " + sSide + " program and arguments from '" + sSide + "' option."; // Now split the option into sProgram and sArguments; std::vector<std::string> argv; if (CreateArgumentVector(sProgram, argv)) return fb.Error(E_CHILD_SETUP) << ": Failed to split '" + sSide + "' option into program name and arguments."; sProgram = argv[0]; for (size_t nArg = 1; nArg < argv.size(); nArg++) sArguments += (sArguments.empty() ? "" : " ") + argv[nArg]; } else { if (!Options::Instance().IsUserSet(sSide + "-program")) return fb.Error(E_CHILD_SETUP) << ": Either the '" + sSide + "' option or the '" + sSide + "-program' and optionally the '" + sSide + "-arguments' options must be specified."; if (Options::Instance().Option(sSide + "-program", sProgram) || Options::Instance().Option(sSide + "-arguments", sArguments)) return fb.Error(E_CHILD_SETUP) << ": Unable to get '" + sSide + "-program' and/or '" + sSide + "-arguments' from options."; } return 0; }
/******************************************************************** * Optimized reading function: Read as large chunks as possible each * time. We can read at most as much as the length of the delimiter * at once. *******************************************************************/ int ReadDelimData(Feedback &fb, std::istream &s, std::string &sData, const std::string &sDelim) { if (sDelim.empty()) return fb.Error(E_UTILS_READJOB) << ": Empty delimiter."; const size_t nDelimLen = sDelim.size(); char buf[nDelimLen + 1]; s.read(buf, nDelimLen); if (s.gcount() != std::streamsize(nDelimLen) || s.eof() || !s.good()) return 1; int nCtr = 0; char *mit; while((mit = MatchDelim(buf, buf + nDelimLen, sDelim.begin(), sDelim.end())) != buf) { nCtr++; sData.append(buf, mit - buf); size_t nSubMatch = buf + nDelimLen - mit; if (nSubMatch > 0) memmove(buf, mit, nSubMatch); s.read(buf + nSubMatch, nDelimLen - nSubMatch); if (s.gcount() != std::streamsize(nDelimLen - nSubMatch) || s.eof() || !s.good()) { buf[std::max(nDelimLen, nSubMatch + static_cast<size_t>(s.gcount()))] = 0; return 1; } } return 0; }
int ReadJobData(Feedback &fb, std::istream &s, const std::string &sChildOutputMode, std::string &sData) { std::stringstream ssMode(sChildOutputMode); std::string sMode1; ssMode >> sMode1; sData.clear(); if (sMode1 == "EOF") { std::string sLine, sEOF; if (!std::getline(s, sEOF)) return fb.Error(E_UTILS_READJOB) << ": Failed to read leading EOF mark. No more jobs?"; if (int nRet = ReadDelimData(fb, s, sData, "\n" + sEOF + "\n")) return nRet; } else if (sMode1 == "BYTES") { size_t nBytes; s.read(reinterpret_cast<char*>(&nBytes), sizeof(nBytes)); if (s.gcount() != sizeof(nBytes)) return fb.Error(E_UTILS_READJOB) << ": Failed to read byte count."; std::vector<char> v(nBytes); s.read(&(v[0]), nBytes); sData.resize(nBytes); std::copy(v.begin(), v.end(), sData.begin()); if (s.gcount() != nBytes) return fb.Error(E_UTILS_READJOB) << ": Failed to read " << nBytes << " bytes of job data."; } else if (sMode1 == "BIN-EOF") { int nTagLen; ssMode >> nTagLen; std::vector<char> tag(nTagLen); s.read(&tag[0], nTagLen); if (s.gcount() != nTagLen) return fb.Error(E_UTILS_READJOB) << ": Failed to read " << nTagLen << " bytes of leading binary eof tag."; if (int nRet = ReadDelimData(fb, s, sData, std::string(&tag[0]))) return nRet; }