1 /*  $Id: cidtool.cpp 457251 2015-01-21 17:47:30Z kazimird $
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  * Authors:  Dmitry Kazimirov
27  *
28  * File Description: Entry point and command line parsing
29  *                   of the cidtool application.
30  *
31  */
32 
33 #include <ncbi_pch.hpp>
34 
35 #include "cidtool.hpp"
36 
37 #include <connect/services/clparser.hpp>
38 #include <connect/services/grid_app_version_info.hpp>
39 
40 #include <corelib/ncbistre.hpp>
41 #include <corelib/ncbi_config.hpp>
42 
43 
44 USING_NCBI_SCOPE;
45 
CComponentIDToolApp(int argc,const char * argv[])46 CComponentIDToolApp::CComponentIDToolApp(int argc, const char* argv[]) :
47     m_ArgC(argc),
48     m_ArgV(argv)
49 {
50 }
51 
52 #ifdef _DEBUG
53 #define OPT_DEF(opt_type, opt_id) CCommandLineParser::opt_type, opt_id
54 #else
55 #define OPT_DEF(opt_type, opt_id) CCommandLineParser::opt_type
56 #endif
57 
58 struct SOptionDefinition {
59     CCommandLineParser::EOptionType type;
60 #ifdef _DEBUG
61     int opt_id;
62 #endif
63     const char* name_variants;
64     const char* description;
65     int required_options[2];
66 } static const s_OptionDefinitions[eNumberOfOptions] = {
67 
68     {OPT_DEF(ePositionalArgument, eCID), "CID", NULL, {-1}},
69 
70     {OPT_DEF(eOptionWithParameter, eInputFile),
71         INPUT_FILE_OPTION, "Read input from the specified file.", {-1}},
72 
73     {OPT_DEF(eOptionWithParameter, eOutputFile),
74         "o|" OUTPUT_FILE_OPTION, "Save output to the specified file.", {-1}},
75 };
76 
77 struct SCommandDefinition {
78     int (CComponentIDToolApp::*cmd_proc)();
79     const char* name_variants;
80     const char* synopsis;
81     const char* usage;
82     int options[eNumberOfOptions + 1];
83 } static const s_CommandDefinitions[] = {
84 
85     {&CComponentIDToolApp::Cmd_Dump,
86         "dump", "Dump the contents of a CompoundID.",
87         "Print the contents of the CompoundID specified on the "
88         "command line to the standard output stream (or a file).",
89         {eCID, eOutputFile, -1}},
90 
91     {&CComponentIDToolApp::Cmd_Make,
92         "make", "Generate a CompoundID.",
93         "Read CompoundID dump from the standard input stream "
94         "(or the specified file) and print the CompoundID that "
95         "corresponds it.",
96         {eInputFile, -1}},
97 };
98 
99 #define TOTAL_NUMBER_OF_COMMANDS int(sizeof(s_CommandDefinitions) / \
100     sizeof(*s_CommandDefinitions))
101 
Run()102 int CComponentIDToolApp::Run()
103 {
104     const SCommandDefinition* cmd_def;
105     const int* cmd_opt;
106 
107     {
108         CCommandLineParser clparser(GRID_APP_NAME, GRID_APP_VERSION_INFO,
109             "Generate and decode identifiers in CompoundID format.");
110 
111         const SOptionDefinition* opt_def = s_OptionDefinitions;
112         int opt_id = 0;
113         do {
114 #ifdef _DEBUG
115             _ASSERT(opt_def->opt_id == opt_id &&
116                 "EOption order must match positions in s_OptionDefinitions.");
117 #endif
118             clparser.AddOption(opt_def->type, opt_id,
119                 opt_def->name_variants, opt_def->description ?
120                     opt_def->description : kEmptyStr);
121             ++opt_def;
122         } while (++opt_id < eNumberOfOptions);
123 
124         cmd_def = s_CommandDefinitions;
125         for (int i = 0; i < TOTAL_NUMBER_OF_COMMANDS; ++i, ++cmd_def) {
126             clparser.AddCommand(i, cmd_def->name_variants,
127                 cmd_def->synopsis, cmd_def->usage);
128             for (cmd_opt = cmd_def->options; *cmd_opt >= 0; ++cmd_opt)
129                 clparser.AddAssociation(i, *cmd_opt);
130         }
131 
132         try {
133             int cmd_id = clparser.Parse(m_ArgC, m_ArgV);
134             if (cmd_id < 0)
135                 return 0;
136 
137             cmd_def = s_CommandDefinitions + cmd_id;
138         }
139         catch (exception& e) {
140             NcbiCerr << e.what();
141             return 1;
142         }
143 
144         for (cmd_opt = cmd_def->options; *cmd_opt >= 0; ++cmd_opt)
145             MarkOptionAsAccepted(*cmd_opt);
146 
147         const char* opt_value;
148 
149         while (clparser.NextOption(&opt_id, &opt_value)) {
150             MarkOptionAsExplicitlySet(opt_id);
151             switch (EOption(opt_id)) {
152             case eCID:
153                 m_Opts.cid = opt_value;
154                 break;
155             case eInputFile:
156                 if ((m_Opts.input_stream = fopen(opt_value, "rb")) == NULL) {
157                     fprintf(stderr, "%s: %s\n", opt_value, strerror(errno));
158                     return 2;
159                 }
160                 break;
161             case eOutputFile:
162                 if ((m_Opts.output_stream = fopen(opt_value, "wb")) == NULL) {
163                     fprintf(stderr, "%s: %s\n", opt_value, strerror(errno));
164                     return 2;
165                 }
166                 break;
167             default: // Just to silence the compiler.
168                 break;
169             }
170         }
171 
172         opt_id = eNumberOfOptions - 1;
173         do
174             if (IsOptionSet(opt_id))
175                 for (const int* required_opt =
176                         s_OptionDefinitions[opt_id].required_options;
177                                 *required_opt != -1; ++required_opt)
178                     if (!IsOptionSet(*required_opt)) {
179                         fprintf(stderr, GRID_APP_NAME
180                                 ": option '--%s' requires option '--%s'.\n",
181                                 s_OptionDefinitions[opt_id].name_variants,
182                                 s_OptionDefinitions[
183                                         *required_opt].name_variants);
184                         return 2;
185                     }
186         while (--opt_id >= 0);
187 
188         if (IsOptionAcceptedButNotSet(eInputFile)) {
189             m_Opts.input_stream = stdin;
190         }
191         if (IsOptionAcceptedButNotSet(eOutputFile)) {
192             m_Opts.output_stream = stdout;
193         }
194     }
195 
196     try {
197         return (this->*cmd_def->cmd_proc)();
198     }
199     catch (CConfigException& e) {
200         fprintf(stderr, "%s\n", e.GetMsg().c_str());
201         return 2;
202     }
203     catch (CArgException& e) {
204         fprintf(stderr, GRID_APP_NAME " %s: %s\n",
205                 cmd_def->name_variants, e.GetMsg().c_str());
206         return 2;
207     }
208     catch (CException& e) {
209         fprintf(stderr, "%s\n", e.what());
210         return 3;
211     }
212     catch (string& s) {
213         fprintf(stderr, "%s\n", s.c_str());
214         return 4;
215     }
216 }
217 
~CComponentIDToolApp()218 CComponentIDToolApp::~CComponentIDToolApp()
219 {
220     if (IsOptionSet(eInputFile) && m_Opts.input_stream != NULL)
221         fclose(m_Opts.input_stream);
222     if (IsOptionSet(eOutputFile) && m_Opts.output_stream != NULL)
223         fclose(m_Opts.output_stream);
224 }
225 
Cmd_Dump()226 int CComponentIDToolApp::Cmd_Dump()
227 {
228     CCompoundID cid(m_CompoundIDPool.FromString(m_Opts.cid));
229 
230     fprintf(m_Opts.output_stream, "%s\n", cid.Dump().c_str());
231 
232     return 0;
233 }
234 
Cmd_Make()235 int CComponentIDToolApp::Cmd_Make()
236 {
237     string dump;
238 
239     char buffer[1024];
240     size_t bytes_read;
241 
242     do {
243         bytes_read = fread(buffer, 1, sizeof(buffer), m_Opts.input_stream);
244         dump.append(buffer, bytes_read);
245     } while (bytes_read == sizeof(buffer));
246 
247     CCompoundID cid(m_CompoundIDPool.FromDump(dump));
248 
249     puts(cid.ToString().c_str());
250 
251     return 0;
252 }
253 
main(int argc,const char * argv[])254 int main(int argc, const char* argv[])
255 {
256     return CComponentIDToolApp(argc, argv).AppMain(1, argv);
257 }
258