1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 #include <precomp.h>
23 #include <adc_cl.hxx>
24 
25 
26 // NOT FULLY DEFINED SERVICES
27 #include <algorithm>
28 #include <cosv/x.hxx>
29 #include <cosv/file.hxx>
30 #include <cosv/tpl/tpltools.hxx>
31 #include <ary/ary.hxx>
32 #include <tools/tkpchars.hxx>
33 #include <adc_msg.hxx>
34 #include "adc_cmds.hxx"
35 #include "adc_cmd_parse.hxx"
36 #include "cmd_sincedata.hxx"
37 
38 
39 namespace autodoc
40 {
41 
42 CommandLine * CommandLine::pTheInstance_ = 0;
43 
44 const char * const C_sUserGuide =
45 "\n\n\n"
46 "               General Use of Autodoc\n"
47 "               ----------------------\n"
48 "\n"
49 "   Example for C++:\n"
50 "\n"
51 "   -html <OutputDirectory> -name \"UDK 3.x anything\" -lg c++\n"
52 "        -p <ProjName> <ProjectRootDirectory>\n"
53 "            -t <SourceDir_relativeToProjectRoot>\n"
54 "\n"
55 "   There may be several projects specified by -p.\n"
56 "\n"
57 "\n"
58 "   Example for IDL:\n"
59 "\n"
60 "   -html <OutputDirectory> -name \"UDK 3.x anything\" -lg idl\n"
61 "         -t <SourceDir1> <SourceDir2>\n"
62 "\n"
63 "   For both languages, instead of or in addition to -t may be\n"
64 "   used -d (no subdirectories) or -f (just one file). There can\n"
65 "   be multiple arguments after each of these options (-t -d -f).\n"
66 "\n"
67 "\n"
68 "           Replacing @since Tag Content\n"
69 "           ----------------------------\n"
70 "\n"
71 "   In both languages you can give a transformation file to replace\n"
72 "   entries in @since tags by different entries.\n"
73 "   This file is given by the option\n"
74 "       -sincefile <TransformationFilePath>\n"
75 "   This option has to appear between the -html and the -lg option.\n"
76 "   Example:\n"
77 "   -html <OutputDirectory> -sincefile replacesince.txt\n"
78 "       -name \"UDK 3.x anything\" -lg idl -t <SourceDir>\n"
79 "\n"
80 "\n";
81 
82 
83 #if 0   // FUTURE
84 "\n\n\n"
85 "               Use of Autodoc\n"
86 "               --------------\n"
87 "\n"
88 "   Basics:\n"
89 "\n"
90 "   Autodoc may perform different tasks.\n"
91 "\n"
92 "   Possible tasks are\n"
93 "       - parsing source code\n"
94 "       - creating HTML-output.\n"
95 "   On the command line each task starts with a specific\n"
96 "   option:\n"
97 "       '-parse' for parsing source code,\n"
98 "       '-html' for creating HTML.\n"
99 "   All command line options, related to one task, have to follow before\n"
100 "   the starting option of the next task.\n"
101 "\n"
102 "   Within the task '-parse', there may be defined different projects.\n"
103 "   A project definition is started with '-p'.\n"
104 "   All not project specific options within the task '-parse' have to\n"
105 "   appear in front of the first '-p'.\n"
106 "   There can be no project at all. Then all options, available for\n"
107 "   projects, can be used like for one nameless default project, without using\n"
108 "   '-p', but these options still have to appear behind all other\n"
109 "   options of the task '-parse'.\n"
110 "\n"
111 "\n"
112 "   Legend:\n"
113 "\n"
114 "       <SomeText>      Describes an argument.\n"
115 "       'SomeText'      Within '...' is the literal value of an argument.\n"
116 "       +               There can be multiple arguments.\n"
117 "       |               Separator for alternative literal values of an argument.\n"
118 "\n"
119 "\n"
120 "   Syntax:\n"
121 "\n"
122 "   -parse\n"
123 "       -name <RepositoryName>]\n"
124 "       -lg 'c++'|'idl'\n"
125 "       -extg <AdditonalExtensions>+\n"
126 "       -docg 'usehtml'\n"
127 "       -p <ProjectName> <ProjectRootDir>\n"
128 "           -l 'c++'|'idl'\n"
129 "           -ext <AdditonalExtensions>+\n"
130 "           -doc 'usehtml'\n"
131 "           -d <SourceDir_relative2ProjectRootDir_nosubdirs>+\n"
132 "           -t <SourceTree_relative2ProjectRootDir>+\n"
133 "           -f <SourceFile_relative2ProjectRootDir>+\n"
134 "   -html <OutputDir>\n"
135 "       -xlinks <Namespace> <ExternLinksRootDir>\n"
136 "   -i <CommandFilePath>\n"
137 "   -v <VerboseNr>\n"
138 "\n"
139 "\n"
140 "   Detailed Options Description:\n"
141 "\n"
142 "   Option      Arguments\n"
143 "   ----------------------------------------------------------\n"
144 "\n"
145 "   -parse      \n\n"
146 "               Starts the task \"Parse source code\".\n"
147 "               May be omitted, if it would be the first option on the\n"
148 "               command line.\n"
149 "\n"
150 "   -name       <RepositoryName>\n\n"
151 "               This name is used for naming the repository in\n"
152 "               human readable output. In future it may be used also for\n"
153 "               identifiing a repository in searches.\n"
154 "\n"
155 "   -lg         'c++|'idl'\n\n"
156 "               Identifies the programming language to be parsed.\n"
157 "                   'c++':  C++\n"
158 "                           Files with extensions '.h', '.hxx' are parsed.\n"
159 "                   'idl':  UNO-IDL\n"
160 "                           Files with extensions '.idl' are parsed.\n"
161 "               Here the language is set globally for all projects.\n"
162 "               A project can override this by using '-l'.\n"
163 "\n"
164 "   -extg       <.AdditionalExtension>+\n\n"
165 "               Has to follow immediately behind '-lg'.\n"
166 "               Specifies additional extensions, that will be recognised as\n"
167 "               source code files of the previously specified programming\n"
168 "               language.  Each extension has to start with '.'.\n"
169 "               It is possible to include extensionless files, too,\n"
170 "               by the argument '.'\n"
171 "               Here these extensions are set globally for all projects.\n"
172 "               A project can override this by using '-l' and '-ext'.\n"
173 "\n"
174 "   -docg       'html'|'nohtml'\n\n"
175 "               Specifies the default for all comments in source code, so \n"
176 "               that HTML-tags are interpreted as such or else treated as\n"
177 "               regular text.\n"
178 "               Without this option, the default is 'nohtml'.\n"
179 "               Here the default is set globally for all projects.\n"
180 "               A project can override this by using '-doc'.\n"
181 "\n"
182 "   -p          <ProjectName> <ProjectRootDirectory>\n\n"
183 "               ProjectName is used in output as human readable identifier\n"
184 "               for the project. ProjectRootDirectory is the path,\n"
185 "               where the arguments of '-d', '-t' and '-f' are relative to.\n"
186 "               This option can be omitted, then there is no project name\n"
187 "               and all paths are relative to the current working directory.\n"
188 "\n"
189 "   -l          'c++|'idl'\n\n"
190 "               Overrides -lg and -extg for the current project, which is\n"
191 "               specified by the last previous '-p'.\n"
192 "               For details see at option '-lg'.\n"
193 "\n"
194 "   -ext        <.AdditionalExtension>+\n\n"
195 "               Can be used only immediately behind '-l'.\n"
196 "               Overrides -extg for the current project, which is\n"
197 "               specified by the last previous '-p'.\n"
198 "               For details see at option '-extg'.\n"
199 "\n"
200 "   -doc        'html'|'nohtml'\n\n"
201 "               Overrides -docg for the current project, which is\n"
202 "               specified by the last previous '-p'.\n"
203 "               For details see at option '-docg'.\n"
204 "\n"
205 "   -d          <SourceDir_relative2ProjectRootDir_nosubdirs>+\n\n"
206 "               For the current project all files in the given\n"
207 "               directories are parsed, which have valid extensions.\n"
208 "               Subdirectories are NOT parsed.\n"
209 "\n"
210 "   -t          <SourceTree_relative2ProjectRootDir>+\n\n"
211 "               For the current project all files in the given\n"
212 "               directories AND its subdirectories are parsed, which\n"
213 "               have valid extensions.\n"
214 "\n"
215 "   -f          <SourceFile_relative2ProjectRootDir>+\n\n"
216 "               For the current project and language the given files\n"
217 "               are parsed. It doesn't matter, if their extensions match\n"
218 "               the valid extensions.\n"
219 "\n"
220 "   -html       <OutputRootDir>\n\n"
221 "               Starts the task \"Create HTML output\".\n"
222 "\n"
223 "   -xlinks     <Namespace> <ExternLinksRootDir>\n\n"
224 "               This option allows, to create links to external\n"
225 "               HTML-documents.\n"
226 "               For all source code objects (like classes or functions)\n"
227 "               which belong in the given namespace, the given root\n"
228 "               directory is used as a base for links to them.\n"
229 "               Presently, this works only for C++-mappings of IDL-items.\n"
230 "               The given namespace has to be absolute.\n"
231 "\n"
232 "   -i          <CommandFilePath>\n\n"
233 "               This option is replaced by the contents of the given\n"
234 "               file. The file has to be ASCII and each option\n"
235 "               has to start in the first column of a new line.\n"
236 "               So each valid line starts with a '-'.\n"
237 "               Empty lines are allowed.\n"
238 "               Comment lines have to start with '#'\n"
239 "\n"
240 "   -v          <VerboseNumber>\n\n"
241 "               Show details during parsing:\n"
242 "                   2    shows each parsed letter,\n"
243 "                   4    shows stored objects.\n"
244 "                   1    shows recognised tokens.\n"
245 "               These bit-values can be combined.\n"
246 "               This option suppresses errors, because of\n"
247 "               missing output options (no '-html').\n";
248 #endif // 0, FUTURE
249 
250 
251 CommandLine::CommandLine()
252     :   nDebugStyle(0),
253         pSinceTransformator(new command::SinceTagTransformationData),
254         aCommands(),
255         bInitOk(false),
256         pCommand_CreateHtml(0),
257         pReposy( & ary::Repository::Create_() ),
258         bCpp(false),
259         bIdl(false)
260 {
261     csv_assert(pTheInstance_ == 0);
262     pTheInstance_ = this;
263 }
264 
265 CommandLine::~CommandLine()
266 {
267     csv::erase_container_of_heap_ptrs(aCommands);
268     pTheInstance_ = 0;
269 }
270 
271 int
272 CommandLine::Run() const
273 {
274     Cout() << "\nAutodoc version 2.2.5"
275            << "\n---------------------"
276            << "\n" << Endl();
277 
278     bool
279         ok = true;
280     for ( CommandList::const_iterator it = aCommands.begin();
281           ok AND it != aCommands.end();
282           ++it )
283     {
284         ok = (*it)->Run();
285     }
286 
287     if (pCommand_CreateHtml != 0)
288     {
289         StreamStr aDiagnosticMessagesFile(700);
290         aDiagnosticMessagesFile
291             << pCommand_CreateHtml->OutputDir()
292             << csv::ploc::Delimiter()
293             << "Autodoc_DiagnosticMessages.txt";
294         TheMessages().WriteFile(aDiagnosticMessagesFile.c_str());
295     }
296 
297     return ok ? 0 : 1;
298 }
299 
300 CommandLine &
301 CommandLine::Get_()
302 {
303     csv_assert(pTheInstance_ != 0);
304     return *pTheInstance_;
305 }
306 
307 bool
308 CommandLine::DoesTransform_SinceTag() const
309 {
310     return pSinceTransformator->DoesTransform();
311 }
312 
313 //bool
314 //CommandLine::Strip_SinceTagText( String & io_sSinceTagValue ) const
315 //{
316 //    return pSinceTransformator->StripSinceTagText(io_sSinceTagValue);
317 //}
318 
319 const String &
320 CommandLine::DisplayOf_SinceTagValue( const String & i_sVersionNumber ) const
321 {
322     return pSinceTransformator->DisplayOf(i_sVersionNumber);
323 }
324 
325 void
326 CommandLine::do_Init( int                 argc,
327                       char *              argv[] )
328 {
329   try
330   {
331     bInitOk = false;
332     StringVector    aParameters;
333 
334     char * * itpEnd = &argv[0] + argc;
335     for ( char * * itp = &argv[1]; itp != itpEnd; ++itp )
336     {
337      	if ( strncmp(*itp, "-I:", 3) != 0 )
338             aParameters.push_back(String(*itp));
339         else
340             load_IncludedCommands(aParameters, (*itp)+3);
341     }
342 
343     StringVector::const_iterator itEnd = aParameters.end();
344     for ( StringVector::const_iterator it = aParameters.begin();
345           it != itEnd;
346         )
347     {
348         if ( *it == command::C_opt_Verbose )
349             do_clVerbose(it,itEnd);
350         else if ( *it == command::C_opt_LangAll
351                   OR *it == command::C_opt_Name
352                   OR *it == command::C_opt_DevmanFile )
353             do_clParse(it,itEnd);
354         else if (*it == command::C_opt_CreateHtml)
355             do_clCreateHtml(it,itEnd);
356         else if (*it == command::C_opt_SinceFile)
357             do_clSinceFile(it,itEnd);
358         else if (*it == command::C_opt_ExternNamespace)
359         {
360             sExternNamespace = *(++it);
361             ++it;
362             if ( strncmp(sExternNamespace.c_str(), "::", 2) != 0)
363             {
364              	throw command::X_CommandLine(
365                         "-extnsp needs an absolute qualified namespace, starting with \"::\"."
366                         );
367             }
368         }
369         else if (*it == command::C_opt_ExternRoot)
370         {
371             ++it;
372             StreamLock sl(1000);
373             if ( csv::compare(*it, 0, "http://", 7) != 0 )
374             {
375                 sl() << "http://" << *it;
376             }
377             if ( *(sl().end()-1) != '/')
378                 sl() << '/';
379             sExternRoot = sl().c_str();
380 
381             ++it;
382         }
383 //        else if (*it == command::C_opt_CreateXml)
384 //            do_clCreateXml(it,itEnd);
385 //        else if (command::C_opt_Load)
386 //            do_clLoad(it,itEnd);
387 //        else if (*it == command::C_opt_Save)
388 //            do_clSave(it,itEnd);
389         else if (*it == "-h" OR *it == "-?" OR *it == "?")
390             // Leads to displaying help, because bInitOk stays on false.
391          	return;
392         else if ( *it == command::C_opt_Parse )
393             // Only for backwards compatibility.
394             //   Just ignore "-parse".
395             ++it;
396         else
397         {
398             StreamLock sl(200);
399          	throw command::X_CommandLine(
400                             sl() << "Unknown commandline option \""
401                                  << *it
402                                  << "\"."
403                                  << c_str );
404         }
405     }   // end for
406     sort_Commands();
407 
408     bInitOk = true;
409 
410   }   // end try
411   catch ( command::X_CommandLine & xxx )
412   {
413     xxx.Report( Cerr() );
414   }
415   catch ( csv::Exception & xxx )
416   {
417     xxx.GetInfo( Cerr() );
418   }
419 }
420 
421 void
422 CommandLine::do_PrintUse() const
423 {
424     Cout() << C_sUserGuide << Endl();
425 }
426 
427 bool
428 CommandLine::inq_CheckParameters() const
429 {
430     if (NOT bInitOk OR aCommands.size() == 0)
431         return false;
432     return true;
433 }
434 
435 void
436 CommandLine::load_IncludedCommands( StringVector &      out,
437                                     const char *        i_filePath )
438 {
439     CharacterSource
440         aIncludedCommands;
441     csv::File
442         aFile(i_filePath, csv::CFM_READ);
443     if (NOT aFile.open())
444     {
445      	Cerr() << "Command include file \""
446                << i_filePath
447                << "\" not found."
448                << Endl();
449         throw command::X_CommandLine("Invalid file in option -I:<command-file>.");
450     }
451     aIncludedCommands.LoadText(aFile);
452     aFile.close();
453 
454     bool bInToken = false;
455     StreamLock aTransmit(200);
456     for ( ; NOT aIncludedCommands.IsFinished(); aIncludedCommands.MoveOn() )
457     {
458         if (bInToken)
459         {
460             if (aIncludedCommands.CurChar() <= 32)
461             {
462                 const char *
463                     pToken = aIncludedCommands.CutToken();
464                 bInToken = false;
465 
466              	if ( strncmp(pToken, "-I:", 3) != 0 )
467              	{
468              	    aTransmit().seekp(0);
469              	    aTransmit() << pToken;
470              	    aTransmit().replace_all('\\', *csv::ploc::Delimiter());
471              	    aTransmit().replace_all('/', *csv::ploc::Delimiter());
472                     out.push_back(String(aTransmit().c_str()));
473              	}
474                 else
475                     load_IncludedCommands(out, pToken+3);
476             }
477         }
478         else
479         {
480             if (aIncludedCommands.CurChar() > 32)
481             {
482                 aIncludedCommands.CutToken();
483                 bInToken = true;
484             }
485         }   // endif (bInToken) else
486 
487     }   // end while()
488 }
489 
490 namespace
491 {
492 inline int
493 v_nr(StringVector::const_iterator it)
494 {
495  	return int( *(*it).c_str() ) - int('0');
496 }
497 }   // anonymous namespace
498 
499 void
500 CommandLine::do_clVerbose(  opt_iter &          it,
501                             opt_iter            itEnd )
502 {
503     ++it;
504     if ( it == itEnd ? true : v_nr(it) < 0 OR v_nr(it) > 7 )
505         throw command::X_CommandLine( "Missing or invalid number in -v option." );
506     nDebugStyle = v_nr(it);
507     ++it;
508 }
509 
510 void
511 CommandLine::do_clParse( opt_iter &          it,
512                          opt_iter            itEnd )
513 {
514     command::Command *
515         pCmd_Parse = new command::Parse;
516     pCmd_Parse->Init(it, itEnd);
517     aCommands.push_back(pCmd_Parse);
518 }
519 
520 void
521 CommandLine::do_clCreateHtml( opt_iter &          it,
522                               opt_iter            itEnd )
523 {
524     pCommand_CreateHtml = new command::CreateHtml;
525     pCommand_CreateHtml->Init(it, itEnd);
526     aCommands.push_back(pCommand_CreateHtml);
527 }
528 
529 void
530 CommandLine::do_clSinceFile( opt_iter &          it,
531                              opt_iter            itEnd )
532 {
533     pSinceTransformator->Init(it, itEnd);
534 }
535 
536 
537 namespace
538 {
539 
540 struct Less_RunningRank
541 {
542     bool                operator()(
543                             const command::Command * const &
544                                                 i1,
545                             const command::Command * const &
546                                                 i2 ) const
547                         { return i1->RunningRank() < i2->RunningRank(); }
548 };
549 
550 }   // anonymous namespace
551 
552 
553 
554 void
555 CommandLine::sort_Commands()
556 {
557     std::sort( aCommands.begin(),
558                aCommands.end(),
559                Less_RunningRank() );
560 }
561 
562 }   // namespace autodoc
563