1 //@copyright_begin
2 // ================================================================
3 // Copyright Notice
4 // Copyright (C) 1998-2004 by Joe Linoff
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the
8 // "Software"), to deal in the Software without restriction, including
9 // without limitation the rights to use, copy, modify, merge, publish,
10 // distribute, sublicense, and/or sell copies of the Software, and to
11 // permit persons to whom the Software is furnished to do so, subject to
12 // the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 // IN NO EVENT SHALL JOE LINOFF BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 // OTHER DEALINGS IN THE SOFTWARE.
24 //
25 // Comments and suggestions are always welcome.
26 // Please report bugs to http://ccdoc.sourceforge.net/ccdoc
27 // ================================================================
28 //@copyright_end
29 #include "switches.h"
30 #include <fstream>
31 #include <cstdio>
32 #include <cstring>
33
34 #ifndef CCDOC_CID
35 #define CCDOC_CID "test"
36 #endif
37
38 #ifndef CCDOC_VERSION
39 // This variable is automatically updated by release.pl.
40 #define CCDOC_VERSION "v08r41 2004/09/29"
41 #endif
42
43 // ================================================================
44 // This static variable allows the header version
45 // to be queried at runtime.
46 // ================================================================
47 namespace {
48 char ccdoc_rcsid[] = "$Id: switches.cc,v 1.24 2004/09/30 04:16:07 jlinoff Exp $";
49 }
50
51 // ================================================================
52 // Constructor.
53 // ================================================================
switches(int argc,char ** argv)54 ccdoc::switches::switches(int argc,char** argv) {
55 ccdoc_assert( argc );
56 ccdoc_assert( argv != 0 );
57
58 m_ok = true;
59 m_help = false;
60 m_program_name = argv[0];
61 m_verbose = false;
62 m_verbose_format = true;
63 m_index = false;
64 m_default_root = "@root";
65 m_root = m_default_root;
66 m_rootfile = "";
67 m_dospaths = false;
68 m_jdsds = true; // Issue 0082
69
70 m_doxygen = true; // Issues 0162 and 0163
71
72 m_rptcfuns = false; // Issue 0133
73 m_rptcsd = true; // Issue 0026
74 m_rptcsi = 4; // Issue 0044
75 m_rptdpa = false; // Issue 0028
76 m_rptdpd = false; // Issue 0030
77 m_rptdpv = false; // Issue 0029
78 m_rptfwcf = false; // Issue 0045
79 m_rpthpc = true; // Issue 0026
80 m_rptim = true;
81 m_rptmac = false;
82 m_rptmac1 = false; // Issue 00153
83 m_rptpri = false;
84 m_rptpro = false;
85 m_rptpub = true;
86 m_rptsci = true; // Issue 0072
87 m_rpttyp = true;
88 m_rptun = true;
89 m_rptsrc = false; // Report source info.
90
91 string rptctcs = "iso-8859-1";
92
93 m_rptdefa = "unascribed"; // Issue 0063
94 m_rptdefasd = "automatically generated"; // Issue 0063
95 m_rptdefsd = "undocumented"; // Issue 0063
96 m_rptdefv = "unknown"; // Issue 0063
97 m_rptctcs = rptctcs; // Issue 0074
98
99 m_maxpathlen = 128;
100 m_cdsm = true;
101 m_tcms = false; // r33 - ignore template class methods
102 m_rptmlcei = 32; // Issue 0159
103 m_rptmlcifi = 32; // Issue 0159
104
105 m_version = "ccdoc ";
106 m_version += CCDOC_VERSION;
107 m_version += " ";
108 m_version += CCDOC_CID;
109 bool report_args = false;
110 bool version_flag = false;
111
112 // Insert the definition for __ccdoc__
113 {
114 string key = "__ccdoc__";
115 string value = "1";
116 m_defines.insert( make_pair(key,value) );
117 }
118
119 // Process the switches.
120 for(int i=0;i<argc;++i) {
121 if(argv[i]) {
122 string str = argv[i];
123 m_switches.push_back(str);
124
125 // ================================================
126 // Help.
127 // ================================================
128 if( str == "-h" || str == "-help" ) {
129 // Help was specified, report
130 // the usage and exit.
131 help();
132 m_ok = false;
133 break;
134 }
135
136 // ================================================
137 // Simple flag switches.
138 // ================================================
139 if( str == "-args" ) {report_args = true; continue;}
140 if( str == "-cdsm" ) {m_cdsm = true; continue;}
141 if( str == "-cid" ) {version_flag = true; continue;}
142 if( str == "-dospaths" ) {m_dospaths = true; continue;}
143 if( str == "-doxygen" ) {m_doxygen = true; continue;}
144 if( str == "-jdsds" ) {m_jdsds = true; continue;}
145 if( str == "-index" ) {m_index = true; continue;}
146 if( str == "-macros" ) {m_rptmac = true; continue;}
147 if( str == "-nocdsm" ) {m_cdsm = false; continue;}
148 if( str == "-nocout" ) {s_log.remove(&cout); continue;}
149 if( str == "-nodoxygen" ) {m_doxygen = false; continue;}
150 if( str == "-nojdsds" ) {m_jdsds = false; continue;}
151 if( str == "-nomacros" ) {m_rptmac = false; continue;}
152 if( str == "-noprivate" ) {m_rptpri = false; continue;}
153 if( str == "-noprotected") {m_rptpro = false; continue;}
154 if( str == "-nopublic" ) {m_rptpub = false; continue;}
155 if( str == "-norptcfuns" ) {m_rptcfuns = false; continue;}
156 if( str == "-norptcsd" ) {m_rptcsd = false; continue;}
157 if( str == "-norptcsi" ) {m_rptcsi = 4; continue;}
158 if( str == "-norptdpa" ) {m_rptdpa = false; continue;}
159 if( str == "-norptdpd" ) {m_rptdpd = false; continue;}
160 if( str == "-norptdpv" ) {m_rptdpv = false; continue;}
161 if( str == "-norptfwcf" ) {m_rptfwcf = false; continue;}
162 if( str == "-norpthpc" ) {m_rpthpc = false; continue;}
163 if( str == "-norptim" ) {m_rptim = false; continue;}
164 if( str == "-norptmac" ) {m_rptmac = false; continue;}
165 if( str == "-norptmac1" ) {m_rptmac1 = false; continue;}
166 if( str == "-norptpri" ) {m_rptpri = false; continue;}
167 if( str == "-norptpro" ) {m_rptpro = false; continue;}
168 if( str == "-norptpub" ) {m_rptpub = false; continue;}
169 if( str == "-norptsci" ) {m_rptsci = false; continue;}
170 if( str == "-norptsrc" ) {m_rptsrc = false; continue;}
171 if( str == "-norpttyp" ) {m_rpttyp = false; continue;}
172 if( str == "-norptun" ) {m_rptun = false; continue;}
173 if( str == "-notcms" ) {m_tcms = false; continue;}
174 if( str == "-notypedefs" ) {m_rpttyp = false; continue;}
175 if( str == "-nounions" ) {m_rptun = false; continue;}
176 if( str == "-nov" ) {m_verbose = false; continue;}
177 if( str == "-novf" ) {m_verbose_format = false; continue;}
178 if( str == "-nowarn" ) {s_log.disable_warnings(); continue;}
179 if( str == "-private" ) {m_rptpri = true; continue;}
180 if( str == "-protected" ) {m_rptpro = true; continue;}
181 if( str == "-public" ) {m_rptpub = true; continue;}
182 if( str == "-rptcfuns" ) {m_rptcfuns = true; continue;}
183 if( str == "-rptcsd" ) {m_rptcsd = true; continue;}
184 if( str == "-rptdpa" ) {m_rptdpa = true; continue;}
185 if( str == "-rptdpd" ) {m_rptdpd = true; continue;}
186 if( str == "-rptdpv" ) {m_rptdpv = true; continue;}
187 if( str == "-rptfwcf" ) {m_rptfwcf = true; continue;}
188 if( str == "-rpthpc" ) {m_rpthpc = true; continue;}
189 if( str == "-rptim" ) {m_rptim = true; continue;}
190 if( str == "-rptmac" ) {m_rptmac = true; continue;}
191 if( str == "-rptmac1" ) {m_rptmac1 = true; continue;}
192 if( str == "-rptpri" ) {m_rptpri = true; continue;}
193 if( str == "-rptpro" ) {m_rptpro = true; continue;}
194 if( str == "-rptpub" ) {m_rptpub = true; continue;}
195 if( str == "-rptsci" ) {m_rptsci = true; continue;}
196 if( str == "-rptsrc" ) {m_rptsrc = true; continue;}
197 if( str == "-rpttyp" ) {m_rpttyp = true; continue;}
198 if( str == "-rptun" ) {m_rptun = true; continue;}
199 if( str == "-tcms" ) {m_tcms = true; continue;}
200 if( str == "-typedefs" ) {m_rpttyp = true; continue;}
201 if( str == "-unions" ) {m_rptun = true; continue;}
202 if( str == "-v" ) {m_verbose = true; continue;}
203 if( str == "-version" ) {version_flag = true; continue;}
204 if( str == "-vf" ) {m_verbose_format = true; continue;}
205 if( str == "-warn" ) {s_log.enable_warnings(); continue;}
206
207 // ================================================
208 // Value switches.
209 // ================================================
210 if( get_arg("-bg" ,str,i,argc,argv) ) {m_bgcolor = str; continue;}
211 if( get_arg("-db" ,str,i,argc,argv) ) {m_db = str; continue;}
212 if( get_arg("-fg" ,str,i,argc,argv) ) {m_fgtextcolor = str; continue;}
213 if( get_arg("-fglink" ,str,i,argc,argv) ) {m_fglinkcolor = str; continue;}
214 if( get_arg("-fgtext" ,str,i,argc,argv) ) {m_fgtextcolor = str; continue;}
215 if( get_arg("-fgvlink" ,str,i,argc,argv) ) {m_fgvlinkcolor = str; continue;}
216 if( get_arg("-files" ,str,i,argc,argv) ) {load_files(str); continue;}
217 if( get_arg("-header" ,str,i,argc,argv) ) {m_header = str; continue;}
218 if( get_arg("-htm" ,str,i,argc,argv) ) {m_html = str; continue;}
219 if( get_arg("-html" ,str,i,argc,argv) ) {m_html = str; continue;}
220 if( get_arg("-imageurl" ,str,i,argc,argv) ) {m_imgurl = str; continue;}
221 if( get_arg("-imgurl" ,str,i,argc,argv) ) {m_imgurl = str; continue;}
222 if( get_arg("-log" ,str,i,argc,argv) ) {s_log.insert(str); continue;}
223 if( get_arg("-meta" ,str,i,argc,argv) ) {m_meta = str; continue;}
224 if( get_arg("-pkg" ,str,i,argc,argv) ) {m_pkg = str; continue;}
225 if( get_arg("-root" ,str,i,argc,argv) ) {m_root = str; continue;}
226 if( get_arg("-rootfile" ,str,i,argc,argv) ) {m_rootfile = str; continue;}
227 if( get_arg("-rootpurl" ,str,i,argc,argv) ) {m_rooturl = str; continue;}
228 if( get_arg("-rooturl" ,str,i,argc,argv) ) {m_rooturl = str; continue;}
229 if( get_arg("-rptctcs" ,str,i,argc,argv) ) {m_rptctcs = str; continue;}
230 if( get_arg("-rptdefa" ,str,i,argc,argv) ) {m_rptdefa = str; continue;}
231 if( get_arg("-rptdefasd" ,str,i,argc,argv) ) {m_rptdefasd = str; continue;}
232 if( get_arg("-rptdefsd" ,str,i,argc,argv) ) {m_rptdefsd = str; continue;}
233 if( get_arg("-rptdefv" ,str,i,argc,argv) ) {m_rptdefv = str; continue;}
234 if( get_arg("-sourceurl" ,str,i,argc,argv) ) {m_srcurl = str; continue;}
235 if( get_arg("-srcurl" ,str,i,argc,argv) ) {m_srcurl = str; continue;}
236 if( get_arg("-trailer" ,str,i,argc,argv) ) {m_trailer = str; continue;}
237
238 if( get_arg("-maxpathlen",str,i,argc,argv) ) {
239 m_maxpathlen = atoi( str.c_str() );
240 continue;
241 }
242 if( get_arg("-rptcsi",str,i,argc,argv) ) {
243 m_rptcsi = atoi( str.c_str() );
244 continue;
245 }
246 if( get_arg("-rptmlcei",str,i,argc,argv) ) {
247 m_rptmlcei = atoi( str.c_str() );
248 continue;
249 }
250 if( get_arg("-rptmlcifi",str,i,argc,argv) ) {
251 m_rptmlcifi = atoi( str.c_str() );
252 continue;
253 }
254 if( get_arg("-putenv",str,i,argc,argv) ) {
255 putenv(str);
256 continue;
257 }
258 if( get_arg("-ctf",str,i,argc,argv) ) {
259 s_log.warning()
260 << "The -ctf switch has been deprecated, use -db instead.\n"
261 << s_log.enable();
262 m_db = str;
263 continue;
264 }
265 if( str[0] == '-' && str[1] == 'D' ) {
266 string errstr = str;
267 str.erase(0,2);
268 //s_log << "DEBUG: -D '" << str << "'\n";
269 // Did the user did specify a value?
270 string::size_type pos = str.find('=');
271 string value = "1";
272 if( pos < str.size() ) {
273 value = str;
274 value.erase(0,pos+1);
275 str.erase(pos,str.size());
276 }
277 //s_log << "DEBUG: -D key='" << str << "' val='" << value << "'\n";
278 if( str.size() == 0 ) {
279 s_log.warning()
280 << "Illegal NULL key argument to '"
281 << errstr
282 << "' was ignored.\n"
283 << s_log.enable();
284 }
285 m_defines.insert( make_pair(str,value) );
286 continue;
287 }
288 if( str[0] == '-' && str[1] == 'U' ) {
289 string errstr = str;
290 str.erase(0,2);
291 if( str.size() == 0 ) {
292 s_log.warning()
293 << "Illegal NULL argument to '"
294 << errstr
295 << "' was ignored.\n"
296 << s_log.enable();
297 }
298 m_undefines.insert(str);
299 //s_log << "DEBUG: -U '" << str << "'\n";
300 continue;
301 }
302
303 // ================================================
304 // Files
305 // ================================================
306 if(i) {
307 load_file(str);
308 }
309 }
310 }
311
312 if( report_args || m_verbose ) {
313 for(int i=0;i<argc;++i) {
314 if(i)
315 s_log << " ";
316 s_log << argv[i];
317 }
318 s_log << "\n";
319 }
320 if( version_flag ) {
321 s_log << m_version << "\n";
322 exit(0);
323 }
324
325 // Make sure the -db switch was specified
326 // (if help wasn't specified).
327 if( ok() ) {
328 // Make sure that the db exists.
329 if( m_db.size() == 0 ) {
330 m_ok = false;
331 if( version_flag == false ) {
332 s_log << "\n";
333 s_log << "ERROR: Ccdoc database (-db <file>) not specified.\n";
334 s_log << " Type ccdoc -h for more information.\n";
335 s_log << "\n";
336 }
337 }
338 }
339 // Make sure that the user didn't specify -meta and -rptctcs at
340 // the same time.
341 if( ok() ) {
342 if( m_meta.size() && m_rptctcs != rptctcs ) {
343 s_log.warning()
344 << "The -meta and -rptctcs switches are mutually exclusive.\n"
345 << "\tThe -rptctcs switch will be ignored.\n"
346 << s_log.enable();
347 }
348 }
349
350 if( ok() ) {
351 if( m_rptmac1 )
352 m_rptmac = true;
353 }
354 }
355 // ================================================================
356 // Destructor.
357 // ================================================================
~switches()358 ccdoc::switches::~switches() {
359 }
360 // ================================================================
361 // Get arg.
362 // ================================================================
get_arg(const char * sw,string & str,int & i,int argc,char ** argv)363 bool ccdoc::switches::get_arg(const char* sw,
364 string& str,
365 int& i,
366 int argc,
367 char** argv)
368 {
369 if( str == sw ) {
370 if( ++i >= argc ) {
371 s_log << "ERROR: Missing argument for switch '"
372 << argv[i-1]
373 << "'\n";
374 m_ok = false;
375 return false;
376 }
377 str = argv[i];
378 return true;
379 }
380 return false;
381 }
382 // ================================================================
383 // Load a file.
384 // ================================================================
load_file(const string & file)385 void ccdoc::switches::load_file(const string& file)
386 {
387 if( file[0] == '-' ) {
388 // The user might have specified an invalid
389 // switch, warn them but then add it as a file.
390 s_log.warning()
391 << "Switch '"
392 << file
393 << "' is treated as a file.\n"
394 << s_log.enable();
395 }
396 // This is assumed to be a file.
397 ifstream is(file.c_str());
398 if( !is ) {
399 #if defined(_MSC_VER)
400 // Issue 0007
401 // This only works for the MSVC version of the program.
402 // Under DOS, this error may have occurred because the
403 // user specified a wildcard. Try to convert the file to a list.
404 string tmp;
405 string cmd;
406 int st;
407 tmp = "ccdoc_msdos.tmp";
408 // Issue 0129
409 // Changed
410 // cmd = "DIR /B /S /O:N "
411 // tp
412 // cmd = "DIR /B /O:N "
413 // The /S switch was causing unwanted side effects.
414 //
415 // Issue 0180
416 // Changed
417 // cmd = "DIR /B /O:N file"
418 // to
419 // cmd = "DIR /B /O:N \"file\"
420 // The lack of quotes caused problems for directories
421 // and files that had embedded spaces.
422 //OLD: cmd = "DIR /B /O:N " + file + " > " + tmp + "\n";
423 cmd = "DIR /B /O:N \"" + file + "\" > " + tmp + "\n";
424 if( verbose() ) {
425 s_log << cmd << "\n";
426 }
427 st = system(cmd.c_str());
428 if( verbose() ) {
429 s_log << "status = " << st << "\n";
430 }
431 if( st == 0 ) {
432 // Issue 0129:
433 // "fix" the entries in the load file by pre-pending
434 // the leading directory. I tried to do this by using
435 // the /S switch but that didn't work because that
436 // switch generates the long files names AND all files
437 // in subdirectories.
438 string prefix;
439 size_t last = file.find_last_of("\\");
440 if( last != string::npos ) {
441 prefix = file.substr(0,last+1);
442 load_files(tmp,prefix.c_str());
443 }
444 else {
445 load_files(tmp);
446 }
447 cmd = "DEL " + tmp + "\n";
448 system(cmd.c_str());
449 return;
450 }
451 #endif
452 s_log.warning()
453 << "File '"
454 << file
455 << "' cannot be read so it will be ignored.\n"
456 << s_log.enable();
457 }
458 else {
459 // Only add files that can be read.
460 m_files.push_back( file );
461 }
462 }
463 // ================================================================
464 // Load a file that contains a list of files.
465 // ================================================================
load_files(const string & file,const char * prefix)466 void ccdoc::switches::load_files(const string& file,const char* prefix)
467 {
468 // The user specified a list of files,
469 // open it and load the files in the internal m_files
470 // vector.
471 ifstream is(file.c_str());
472 if( is.fail() || is.bad() ) {
473 s_log.warning()
474 << "Can't read -files " << file.c_str() << " so it will be ignored.\n"
475 << s_log.enable();
476 }
477 else {
478 static char nbuf[65536];
479 string token;
480 while( is.getline(nbuf,sizeof(nbuf)) ) {
481 int nbuf_cmp = *nbuf; // eliminate compiler warning
482 if( nbuf_cmp > 32 && nbuf_cmp < 128) {
483 if( verbose() ) {
484 s_log << "loading file " << nbuf << " ...\n";
485 }
486 if( prefix ) {
487 token = prefix;
488 token += nbuf;
489 m_files.push_back( token );
490 }
491 else {
492 m_files.push_back( nbuf );
493 }
494 }
495 }
496 }
497 }
498 // ================================================================
499 // Put env
500 // ================================================================
putenv(string & str) const501 void ccdoc::switches::putenv( string& str ) const
502 {
503 // We need to keep a permanent copy of the environment
504 // variables to be safe on different platforms.
505 const unsigned MAX_ENVS = 32;
506 static unsigned s_putenv_idx = 0;
507 static char s_putenv[MAX_ENVS][4096];
508 ccdoc_assert( s_putenv_idx < MAX_ENVS );
509 ccdoc_assert( str.size() < 4096 );
510 char* putenv_string = s_putenv[ s_putenv_idx ];
511 strcpy( putenv_string, str.c_str() );
512 ::putenv( putenv_string );
513 s_putenv_idx++;
514 }
515 // ================================================================
516 // Load the defines map.
517 // ================================================================
defines(defines_type & out) const518 void ccdoc::switches::defines( defines_type& out ) const
519 {
520 for( defines_type::const_iterator i=m_defines.begin();i!=m_defines.end();++i) {
521 out.insert( make_pair((*i).first,(*i).second) );
522 }
523 }
524 // ================================================================
525 // Load the undefines set.
526 // ================================================================
undefines(undefines_type & out) const527 void ccdoc::switches::undefines( undefines_type& out ) const
528 {
529 for( undefines_type::const_iterator i=m_undefines.begin();i!=m_undefines.end();++i) {
530 out.insert( *i );
531 }
532 }
533