1 /* $Id: blast_formatter.cpp 616448 2020-09-16 13:25:04Z fongah2 $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Christiam Camacho
27 *
28 */
29
30 /** @file blast_formatter.cpp
31 * Stand-alone command line formatter for BLAST.
32 */
33
34 #include <ncbi_pch.hpp>
35 #include <corelib/ncbiapp.hpp>
36 #include <corelib/ncbistre.hpp>
37 #include <serial/iterator.hpp>
38 #include <algo/blast/api/version.hpp>
39 #include <algo/blast/api/remote_blast.hpp>
40 #include <algo/blast/blastinput/blast_input_aux.hpp>
41 #include <algo/blast/format/blast_format.hpp>
42 #include <algo/blast/api/objmgr_query_data.hpp>
43 #include <objtools/data_loaders/blastdb/bdbloader_rmt.hpp>
44 #include <objtools/data_loaders/genbank/gbloader.hpp>
45 #include <objtools/data_loaders/genbank/id2/reader_id2.hpp>
46 #include "blast_app_util.hpp"
47
48
49 #ifndef SKIP_DOXYGEN_PROCESSING
50 USING_NCBI_SCOPE;
51 USING_SCOPE(blast);
52 #endif
53
54 /// The application class
55 class CBlastFormatterApp : public CNcbiApplication
56 {
57 public:
58 /** @inheritDoc */
CBlastFormatterApp()59 CBlastFormatterApp() {
60 CRef<CVersion> version(new CVersion());
61 version->SetVersionInfo(new CBlastVersion());
62 SetFullVersion(version);
63 m_LoadFromArchive = false;
64 m_StopWatch.Start();
65 if (m_UsageReport.IsEnabled()) {
66 m_UsageReport.AddParam(CBlastUsageReport::eVersion, GetVersion().Print());
67 m_UsageReport.AddParam(CBlastUsageReport::eProgram, (string) "blast_formatter");
68 }
69 }
70
~CBlastFormatterApp()71 ~CBlastFormatterApp() {
72 m_UsageReport.AddParam(CBlastUsageReport::eRunTime, m_StopWatch.Elapsed());
73 }
74
75 private:
76 /** @inheritDoc */
77 virtual void Init();
78 /** @inheritDoc */
79 virtual int Run();
80
81 /// Prints the BLAST formatted output
82 int PrintFormattedOutput(void);
83
84 /// Extracts the queries to be formatted
85 /// @param query_is_protein Are the queries protein sequences? [in]
86 CRef<CBlastQueryVector> x_ExtractQueries(bool query_is_protein);
87
88 /// Build the query from a PSSM
89 /// @param pssm PSSM to inspect [in]
90 CRef<CBlastSearchQuery>
91 x_BuildQueryFromPssm(const CPssmWithParameters& pssm);
92
93 /// Package a scope and Seq-loc into a SSeqLoc from a Bioseq
94 /// @param bioseq Bioseq to inspect [in]
95 /// @param scope Scope object to add the sequence data to [in|out]
96 SSeqLoc x_QueryBioseqToSSeqLoc(const CBioseq& bioseq, CRef<CScope> scope);
97
98 void x_AddCmdOptions();
99
100 /// Our link to the NCBI BLAST service
101 CRef<CRemoteBlast> m_RmtBlast;
102
103 /// The source of CScope objects for queries
104 CRef<CBlastScopeSource> m_QueryScopeSource;
105
106 /// Tracks whether results come from an archive file.
107 bool m_LoadFromArchive;
108 CBlastUsageReport m_UsageReport;
109 CStopWatch m_StopWatch;
110 };
111
Init()112 void CBlastFormatterApp::Init()
113 {
114 HideStdArgs(fHideLogfile | fHideConffile | fHideFullVersion | fHideXmlHelp | fHideDryRun);
115
116 auto_ptr<CArgDescriptions> arg_desc(new CArgDescriptions);
117
118 arg_desc->SetUsageContext(GetArguments().GetProgramBasename(),
119 "Stand-alone BLAST formatter client, version "
120 + CBlastVersion().Print());
121
122 arg_desc->SetCurrentGroup("Input options");
123 arg_desc->AddOptionalKey(kArgRid, "BLAST_RID", "BLAST Request ID (RID)",
124 CArgDescriptions::eString);
125
126 // add input file for seq-align here?
127 arg_desc->AddOptionalKey(kArgArchive, "ArchiveFile", "File containing BLAST Archive format in ASN.1 (i.e.: output format 11)",
128 CArgDescriptions::eInputFile);
129 arg_desc->SetDependency(kArgRid, CArgDescriptions::eExcludes, kArgArchive);
130
131 CFormattingArgs fmt_args(false, CFormattingArgs::eIsSAM);
132 fmt_args.SetArgumentDescriptions(*arg_desc);
133
134 arg_desc->SetCurrentGroup("Output configuration options");
135 arg_desc->AddDefaultKey(kArgOutput, "output_file", "Output file name",
136 CArgDescriptions::eOutputFile, "-");
137
138 arg_desc->SetCurrentGroup("Miscellaneous options");
139 arg_desc->AddFlag(kArgParseDeflines,
140 "Should the query and subject defline(s) be parsed?", true);
141 arg_desc->SetCurrentGroup("");
142
143 CDebugArgs debug_args;
144 debug_args.SetArgumentDescriptions(*arg_desc);
145
146 SetupArgDescriptions(arg_desc.release());
147 }
148
149 SSeqLoc
x_QueryBioseqToSSeqLoc(const CBioseq & bioseq,CRef<CScope> scope)150 CBlastFormatterApp::x_QueryBioseqToSSeqLoc(const CBioseq& bioseq,
151 CRef<CScope> scope)
152 {
153 static bool first_time = true;
154 _ASSERT(scope);
155
156 if ( !HasRawSequenceData(bioseq) && first_time ) {
157 _ASSERT(m_QueryScopeSource);
158 m_QueryScopeSource->AddDataLoaders(scope);
159 first_time = false;
160 }
161 else {
162 scope->AddBioseq(bioseq);
163 }
164 CRef<CSeq_loc> seqloc(new CSeq_loc);
165 seqloc->SetWhole().Assign(*bioseq.GetFirstId());
166 return SSeqLoc(seqloc, scope);
167 }
168
169 CRef<CBlastSearchQuery>
x_BuildQueryFromPssm(const CPssmWithParameters & pssm)170 CBlastFormatterApp::x_BuildQueryFromPssm(const CPssmWithParameters& pssm)
171 {
172 if ( !pssm.HasQuery() ) {
173 throw runtime_error("PSSM has no query");
174 }
175 CRef<CScope> scope(new CScope(*CObjectManager::GetInstance()));
176 const CSeq_entry& seq_entry = pssm.GetQuery();
177 if ( !seq_entry.IsSeq() ) {
178 throw runtime_error("Cannot have multiple queries in a PSSM");
179 }
180 SSeqLoc ssl = x_QueryBioseqToSSeqLoc(seq_entry.GetSeq(), scope);
181 CRef<CBlastSearchQuery> retval;
182 retval.Reset(new CBlastSearchQuery(*ssl.seqloc, *ssl.scope));
183 _ASSERT(ssl.scope.GetPointer() == scope.GetPointer());
184 return retval;
185 }
186
187 CRef<CBlastQueryVector>
x_ExtractQueries(bool query_is_protein)188 CBlastFormatterApp::x_ExtractQueries(bool query_is_protein)
189 {
190 CRef<CBlast4_queries> b4_queries = m_RmtBlast->GetQueries();
191 _ASSERT(b4_queries);
192 const size_t kNumQueries = b4_queries->GetNumQueries();
193
194 CRef<CBlastQueryVector> retval(new CBlastQueryVector);
195
196 SDataLoaderConfig dlconfig(query_is_protein, SDataLoaderConfig::eUseNoDataLoaders);
197 dlconfig.OptimizeForWholeLargeSequenceRetrieval(false);
198 m_QueryScopeSource.Reset(new CBlastScopeSource(dlconfig));
199
200 if (b4_queries->IsPssm()) {
201 retval->AddQuery(x_BuildQueryFromPssm(b4_queries->GetPssm()));
202 } else if (b4_queries->IsSeq_loc_list()) {
203 CRef<CScope> scope = m_QueryScopeSource->NewScope();
204 ITERATE(CBlast4_queries::TSeq_loc_list, seqloc,
205 b4_queries->GetSeq_loc_list()) {
206 _ASSERT( !(*seqloc)->GetId()->IsLocal() );
207 CRef<CBlastSearchQuery> query(new CBlastSearchQuery(**seqloc,
208 *scope));
209 retval->AddQuery(query);
210 }
211 } else if (b4_queries->IsBioseq_set()) {
212 CTypeConstIterator<CBioseq> itr(ConstBegin(b4_queries->GetBioseq_set(),
213 eDetectLoops));
214 CRef<CScope> scope(new CScope(*CObjectManager::GetInstance()));
215 for (; itr; ++itr) {
216 SSeqLoc ssl = x_QueryBioseqToSSeqLoc(*itr, scope);
217 CRef<CBlastSearchQuery> query(new CBlastSearchQuery(*ssl.seqloc,
218 *ssl.scope));
219 retval->AddQuery(query);
220 }
221 }
222
223 (void)kNumQueries; // eliminate compiler warning;
224 _ASSERT(kNumQueries == retval->size());
225 return retval;
226 }
227
228 /// Extracts the subject sequence data from remote_blast into a TSeqLocVector.
229 /// All subjects are added to/use the same CScope object
230 /// @param remote_blast Source of subject sequences
231 static TSeqLocVector
s_ConvertSubjects2TSeqLocVector(CRef<CRemoteBlast> remote_blast)232 s_ConvertSubjects2TSeqLocVector(CRef<CRemoteBlast> remote_blast)
233 {
234 TSeqLocVector retval;
235 CRef<CScope> subj_scope(new CScope(*CObjectManager::GetInstance()));
236 if (remote_blast->GetSubjectSeqLocs().empty()) {
237 const list<CRef<CBioseq> > subjects =
238 remote_blast->GetSubjectSequences();
239 ITERATE(list<CRef<CBioseq> >, bioseq, subjects) {
240 subj_scope->AddBioseq(**bioseq);
241 CRef<CSeq_id> seqid = FindBestChoice((*bioseq)->GetId(),
242 CSeq_id::BestRank);
243 const TSeqPos length = (*bioseq)->GetInst().GetLength();
244 CRef<CSeq_loc> sl(new CSeq_loc(*seqid, 0, length-1));
245 retval.push_back(SSeqLoc(sl, subj_scope));
246 }
247 } else {
248 const CBlast4_subject::TSeq_loc_list seqlocs =
249 remote_blast->GetSubjectSeqLocs();
250 ITERATE(CBlast4_subject::TSeq_loc_list, sl, seqlocs) {
251 retval.push_back(SSeqLoc(*sl, subj_scope));
252 }
253 }
254 return retval;
255 }
256
257 bool
s_InitializeSubject(CRef<blast::CBlastDatabaseArgs> db_args,CRef<blast::CBlastOptionsHandle> opts_hndl,CRef<blast::CLocalDbAdapter> & db_adapter,CRef<objects::CScope> & scope)258 s_InitializeSubject(CRef<blast::CBlastDatabaseArgs> db_args,
259 CRef<blast::CBlastOptionsHandle> opts_hndl,
260 CRef<blast::CLocalDbAdapter>& db_adapter,
261 CRef<objects::CScope>& scope)
262 {
263 bool isRemote = false;
264 db_adapter.Reset();
265
266 _ASSERT(db_args.NotEmpty());
267 CRef<CSearchDatabase> search_db = db_args->GetSearchDatabase();
268
269 if (scope.Empty()) {
270 scope.Reset(new CScope(*CObjectManager::GetInstance()));
271 }
272
273 CRef<IQueryFactory> subjects;
274 if ( (subjects = db_args->GetSubjects(scope)) ) {
275 _ASSERT(search_db.Empty());
276 char* bl2seq_legacy = getenv("BL2SEQ_LEGACY");
277 if (bl2seq_legacy) {
278 db_adapter.Reset(new CLocalDbAdapter(subjects, opts_hndl, false));
279 }
280 else {
281 db_adapter.Reset(new CLocalDbAdapter(subjects, opts_hndl, true));
282 }
283 } else {
284 _ASSERT(search_db.NotEmpty());
285 try {
286 // Try to open the BLAST database even for remote searches, as if
287 // it is available locally, it will be better to fetch the
288 // sequence data for formatting from this (local) source
289 CRef<CSeqDB> seqdb = search_db->GetSeqDb();
290 db_adapter.Reset(new CLocalDbAdapter(*search_db));
291 scope->AddDataLoader(RegisterOMDataLoader(seqdb), CBlastDatabaseArgs::kSubjectsDataLoaderPriority);
292 LOG_POST(Info <<"Add local loader " << search_db->GetDatabaseName());
293 } catch (const CSeqDBException&) {
294 SetDiagPostLevel(eDiag_Critical);
295 string remote_loader = kEmptyStr;
296 try {
297 db_adapter.Reset(new CLocalDbAdapter(*search_db));
298 remote_loader = CRemoteBlastDbDataLoader::RegisterInObjectManager
299 (*( CObjectManager::GetInstance()),
300 search_db->GetDatabaseName(),
301 search_db->IsProtein() ? CBlastDbDataLoader::eProtein : CBlastDbDataLoader::eNucleotide,
302 true, CObjectManager::eDefault, CBlastDatabaseArgs::kSubjectsDataLoaderPriority)
303 .GetLoader()->GetName();
304 scope->AddDataLoader(remote_loader, CBlastDatabaseArgs::kSubjectsDataLoaderPriority);
305 SetDiagPostLevel(eDiag_Warning);
306 isRemote = true;
307 LOG_POST(Info <<"Remote " << search_db->GetDatabaseName());
308 }
309 catch (CException & e) {
310 SetDiagPostLevel(eDiag_Warning);
311 NCBI_THROW(CException, eUnknown, "Fail to initialize local or remote DB" );
312 }
313 }
314 }
315 try {
316 const int kGenbankLoaderPriority = 99;
317 CRef<CReader> reader(new CId2Reader);
318 reader->SetPreopenConnection(false);
319 string genbank_loader = CGBDataLoader::RegisterInObjectManager
320 (*( CObjectManager::GetInstance()), reader,CObjectManager::eNonDefault).GetLoader()->GetName();
321 scope->AddDataLoader(genbank_loader, kGenbankLoaderPriority);
322 } catch (const CException& e) {
323 LOG_POST(Info << "Failed to add genbank dataloader");
324 // It's ok not to have genbank loader
325 }
326 return isRemote;
327 }
328
PrintFormattedOutput(void)329 int CBlastFormatterApp::PrintFormattedOutput(void)
330 {
331 int retval = 0;
332 const CArgs& args = GetArgs();
333 const string& kRid = args[kArgRid].HasValue()
334 ? args[kArgRid].AsString() : kEmptyStr;
335 CNcbiOstream& out = args[kArgOutput].AsOutputFile();
336 CFormattingArgs fmt_args(false, CFormattingArgs::eIsSAM) ;
337
338 CRef<CBlastOptionsHandle> opts_handle = m_RmtBlast->GetSearchOptions();
339 CBlastOptions& opts = opts_handle->SetOptions();
340 fmt_args.ExtractAlgorithmOptions(args, opts);
341 {{
342 CDebugArgs debug_args;
343 debug_args.ExtractAlgorithmOptions(args, opts);
344 if (debug_args.ProduceDebugOutput()) {
345 opts.DebugDumpText(NcbiCerr, "BLAST options", 1);
346 }
347 }}
348
349
350 const EBlastProgramType p = opts.GetProgramType();
351 if((fmt_args.GetFormattedOutputChoice() == CFormattingArgs::eSAM) &&
352 (p != eBlastTypeBlastn )) {
353 NCBI_THROW(CInputException, eInvalidInput,
354 "SAM format is only applicable to blastn results" );
355 }
356
357 CRef<CBlastQueryVector> queries =
358 x_ExtractQueries(Blast_QueryIsProtein(p)?true:false);
359 CRef<CScope> scope = queries->GetScope(0);
360 _ASSERT(queries);
361
362 CRef<CBlastDatabaseArgs> db_args(new CBlastDatabaseArgs()); // FIXME, what about rpsblast?
363 int filtering_algorithm = -1;
364 if (m_RmtBlast->IsDbSearch())
365 {
366 CRef<CBlast4_database> db = m_RmtBlast->GetDatabases();
367 _ASSERT(db);
368 _TRACE("Fetching results for " + Blast_ProgramNameFromType(p) + " on "
369 + db->GetName());
370 filtering_algorithm = m_RmtBlast->GetDbFilteringAlgorithmId();
371 CRef<CSearchDatabase> search_db(new CSearchDatabase(db->GetName(), db->IsProtein()
372 ? CSearchDatabase::eBlastDbIsProtein
373 : CSearchDatabase::eBlastDbIsNucleotide));
374
375 if(m_RmtBlast->GetTaxidList().size() > 0) {
376 CSeqDBGiList *gilist = new CSeqDBGiList();
377 gilist->AddTaxIds(m_RmtBlast->GetTaxidList());
378 search_db->SetGiList(gilist);
379 }
380
381 if(m_RmtBlast->GetNegativeTaxidList().size() > 0) {
382 CSeqDBGiList *gilist = new CSeqDBGiList();
383 gilist->AddTaxIds(m_RmtBlast->GetTaxidList());
384 search_db->SetNegativeGiList(gilist);
385 }
386 db_args->SetSearchDatabase(search_db);
387 }
388 else
389 {
390 TSeqLocVector subjects = s_ConvertSubjects2TSeqLocVector(m_RmtBlast);
391 CRef<IQueryFactory> subject_factory(new CObjMgr_QueryFactory(subjects));
392 CRef<CScope> subj_scope = subjects.front().scope;
393 db_args->SetSubjects(subject_factory, subj_scope,
394 Blast_SubjectIsProtein(p)?true:false);
395 }
396
397 CRef<CLocalDbAdapter> db_adapter;
398 bool isRemoteLoader = s_InitializeSubject(db_args, opts_handle, db_adapter, scope);
399
400 const string kTask = m_RmtBlast->GetTask();
401
402 CBlastFormat formatter(opts, *db_adapter,
403 fmt_args.GetFormattedOutputChoice(),
404 static_cast<bool>(args[kArgParseDeflines]),
405 out,
406 fmt_args.GetNumDescriptions(),
407 fmt_args.GetNumAlignments(),
408 *scope,
409 opts.GetMatrixName(),
410 fmt_args.ShowGis(),
411 fmt_args.DisplayHtmlOutput(),
412 opts.GetQueryGeneticCode(),
413 opts.GetDbGeneticCode(),
414 opts.GetSumStatisticsMode(),
415 (!kRid.empty() || isRemoteLoader),
416 filtering_algorithm,
417 fmt_args.GetCustomOutputFormatSpec(),
418 kTask == "megablast",
419 opts.GetMBIndexLoaded(),
420 NULL, NULL,
421 GetCmdlineArgs(GetArguments()));
422 formatter.SetLineLength(fmt_args.GetLineLength());
423 formatter.SetHitsSortOption(fmt_args.GetHitsSortOption());
424 formatter.SetHspsSortOption(fmt_args.GetHspsSortOption());
425 formatter.SetCustomDelimiter(fmt_args.GetCustomDelimiter());
426 if(UseXInclude(fmt_args, args[kArgOutput].AsString())) {
427 formatter.SetBaseFile(args[kArgOutput].AsString());
428 }
429 CRef<CSearchResultSet> results = m_RmtBlast->GetResultSet();
430 formatter.PrintProlog();
431 bool isPsiBlast = ("psiblast" == kTask);
432 if (fmt_args.ArchiveFormatRequested(args))
433 {
434 if(isPsiBlast)
435 {
436 CRef<objects::CPssmWithParameters> pssm = m_RmtBlast->GetPSSM();
437 if(!pssm.Empty())
438 {
439 formatter.WriteArchive(*pssm, *opts_handle, *results, m_RmtBlast->GetPsiNumberOfIterations());
440 }
441 else
442 {
443 CRef<IQueryFactory> query_factory(new CObjMgr_QueryFactory(*queries));
444 formatter.WriteArchive(*query_factory, *opts_handle, *results, m_RmtBlast->GetPsiNumberOfIterations());
445 }
446 }
447 else
448 {
449 CRef<IQueryFactory> query_factory(new CObjMgr_QueryFactory(*queries));
450 formatter.WriteArchive(*query_factory, *opts_handle, *results);
451 }
452 } else {
453 while (1)
454 {
455 BlastFormatter_PreFetchSequenceData(*results, scope,
456 fmt_args.GetFormattedOutputChoice());
457 ITERATE(CSearchResultSet, result, *results) {
458 if(isPsiBlast)
459 {
460 formatter.PrintOneResultSet(**result, queries,
461 m_RmtBlast->GetPsiNumberOfIterations());
462 }
463 else
464 {
465 formatter.PrintOneResultSet(**result, queries);
466 }
467 }
468 // The entire archive file (multiple sets) is formatted in this loop for XML.
469 // That does not work for other formats. Ugly, but that's where it's at now.
470 if (m_LoadFromArchive == false || (fmt_args.GetFormattedOutputChoice() != CFormattingArgs::eXml
471 && fmt_args.GetFormattedOutputChoice() != CFormattingArgs::eXml2
472 && fmt_args.GetFormattedOutputChoice() != CFormattingArgs::eJson
473 && fmt_args.GetFormattedOutputChoice() != CFormattingArgs::eXml2_S
474 && fmt_args.GetFormattedOutputChoice() != CFormattingArgs::eJson_S )
475 || !m_RmtBlast->LoadFromArchive()) {
476 break;
477 }
478 // Reset these for next set from archive
479 results.Reset(m_RmtBlast->GetResultSet());
480 queries.Reset(x_ExtractQueries(Blast_QueryIsProtein(p)?true:false));
481 _ASSERT(queries);
482 if (fmt_args.GetFormattedOutputChoice() == CFormattingArgs::eXml) {
483 scope.Reset(queries->GetScope(0));
484 }
485 else {
486 scope->AddScope(*(queries->GetScope(0)));
487 }
488 s_InitializeSubject(db_args, opts_handle, db_adapter, scope);
489 }
490 }
491 formatter.PrintEpilog(opts);
492 return retval;
493 }
494
495 #define EXIT_CODE__UNKNOWN_RID 1
496 #define EXIT_CODE__SEARCH_PENDING 2
497 #define EXIT_CODE__SEARCH_FAILED 3
498
Run(void)499 int CBlastFormatterApp::Run(void)
500 {
501 int status = 0;
502 const CArgs& args = GetArgs();
503
504 try {
505 SetDiagPostLevel(eDiag_Warning);
506 if (args[kArgArchive].HasValue()) {
507 CNcbiIstream& istr = args[kArgArchive].AsInputFile();
508 try { m_RmtBlast.Reset(new CRemoteBlast(istr)); }
509 catch (const CBlastException& e) {
510 if (e.GetErrCode() == CBlastException::eInvalidArgument) {
511 NCBI_RETHROW(e, CInputException, eInvalidInput,
512 "Invalid input format for BLAST Archive.");
513 }
514 }
515
516 m_LoadFromArchive = true;
517 try {
518 while (m_RmtBlast->LoadFromArchive()) {
519 if(!m_RmtBlast->IsErrMsgArchive()) {
520 status = PrintFormattedOutput();
521 }
522 }
523 } catch (const CSerialException& e) {
524 NCBI_RETHROW(e, CInputException, eInvalidInput,
525 "Invalid input format for BLAST Archive.");
526 }
527 return status;
528 }
529
530 const string kRid = args[kArgRid].AsString();
531 m_RmtBlast.Reset(new CRemoteBlast(kRid));
532 {{
533 CDebugArgs debug_args;
534 CBlastOptions dummy_options;
535 debug_args.ExtractAlgorithmOptions(args, dummy_options);
536 if (debug_args.ProduceDebugRemoteOutput()) {
537 m_RmtBlast->SetVerbose();
538 }
539 }}
540
541 switch (m_RmtBlast->CheckStatus()) {
542 case CRemoteBlast::eStatus_Unknown:
543 cerr << "Unknown/invalid RID '" << kRid << "'." << endl;
544 status = EXIT_CODE__UNKNOWN_RID;
545 break;
546
547 case CRemoteBlast::eStatus_Done:
548 status = PrintFormattedOutput();
549 break;
550
551 case CRemoteBlast::eStatus_Pending:
552 cerr << "RID '" << kRid << "' is still pending." << endl;
553 status = EXIT_CODE__SEARCH_PENDING;
554 break;
555
556 case CRemoteBlast::eStatus_Failed:
557 cerr << "RID '" << kRid << "' has failed" << endl;
558 cerr << m_RmtBlast->GetErrors() << endl;
559 status = EXIT_CODE__SEARCH_FAILED;
560 break;
561
562 default:
563 abort();
564 }
565
566 } CATCH_ALL(status)
567 x_AddCmdOptions();
568 m_UsageReport.AddParam(CBlastUsageReport::eExitStatus, status);
569 return status;
570 }
571
x_AddCmdOptions()572 void CBlastFormatterApp::x_AddCmdOptions()
573 {
574 const CArgs & args = GetArgs();
575 if (args[kArgRid].HasValue()) {
576 m_UsageReport.AddParam(CBlastUsageReport::eRIDInput, args[kArgRid].AsString());
577 }
578 else if (args[kArgArchive].HasValue()) {
579 m_UsageReport.AddParam(CBlastUsageReport::eArchiveInput, true);
580 }
581
582 if(args["outfmt"].HasValue()) {
583 m_UsageReport.AddParam(CBlastUsageReport::eOutputFmt, args["outfmt"].AsString());
584 }
585 }
586
587
588 #ifndef SKIP_DOXYGEN_PROCESSING
main(int argc,const char * argv[])589 int main(int argc, const char* argv[] /*, const char* envp[]*/)
590 {
591 return CBlastFormatterApp().AppMain(argc, argv);
592 }
593 #endif /* SKIP_DOXYGEN_PROCESSING */
594