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