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