/*
* Copyright (C) 1999-2005 Lorenzo Bettini, www.lorenzobettini.it
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "startapp.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string.h>
#include "colors.h"
#include "cmdline.h"
#include "fileutil.h"
#include "messages.h"
#include "copyright.h"
#include "reportbugs.h"
#include "parsetags.h"
#include "htmlgeneratorfactory.h"
#include "xhtmlgeneratorfactory.h"
#include "cssgeneratorfactory.h"
#include "escgeneratorfactory.h"
#include "srcuntabifier.h"
#include "chartranslator.h"
#include "langdefloader.h"
#include "lineoutputgenerator.h"
#include "langmap.h"
#include "regexpengine.h"
#include "docgenerator.h"
// for globals
#include "linenumdigit.h"
#include "globalostream.h"
#include "cmdlineargs.h"
#include "mainoutputbuffer.h"
#include "mainoutputgenerator.h"
using namespace std;
// global output stream
ostream* sout;
#ifdef BUILD_AS_CGI
#include "envmapper.h"
#endif // BUILD_AS_CGI
unsigned int line_num_digit = 0; // num of digits to represent line number
gengetopt_args_info args_info ; // command line structure
static void print_cgi_header();
StartApp::StartApp() :
docgenerator(0), formatter(0), langmap(0), generator_factory(0),
entire_doc (0), verbose (0), cssUrl (0),
use_css (0), is_cgi (0), gen_version(true),
generate_line_num(false), generate_ref(false)
{
}
StartApp::~StartApp()
{
// cout << "destroying StartApp..." << endl;
cmdline_parser_free(&args_info);
if (formatter)
delete formatter;
if (docgenerator)
delete docgenerator;
if (langmap)
delete langmap;
if (generator_factory)
delete generator_factory;
}
int
StartApp::start(int argc, char * argv[])
{
char *docTitle;
char *docHeader; // the buffer with the header
char *docFooter; // the buffer with the footer
const char *header_fileName = 0;
const char *footer_fileName = 0;
unsigned i;
int v;
int tabSpaces = 0;
#ifdef BUILD_AS_CGI
// map environment to parameters if used as CGI
char **temp_argv;
temp_argv = map_environment(&argc, argv);
is_cgi = temp_argv != argv;
argv = temp_argv;
#endif // BUILD_AS_CGI
if((v = cmdline_parser(argc, argv, &args_info)) != 0)
// calls cmdline parser. The user gived bag args if it doesn't return -1
return EXIT_FAILURE;
if (args_info.version_given)
{
print_version ();
print_copyright ();
return EXIT_SUCCESS;
}
if (args_info.help_given)
{
cout << "GNU ";
cmdline_parser_print_help ();
print_reportbugs ();
return EXIT_SUCCESS;
}
bool format_html = (strcmp (args_info.out_format_arg, "html") == 0);
bool format_xhtml = (strcmp (args_info.out_format_arg, "xhtml") == 0);
bool format_esc = (strcmp (args_info.out_format_arg, "esc") == 0);
gen_version = (args_info.gen_version_flag != 0);
const char *ext = 0;
if (! format_html && ! format_xhtml && ! format_esc)
{
cerr << PACKAGE << ": output format " << args_info.out_format_arg
<< " not recognized" << endl;
return EXIT_FAILURE;
}
if (format_html || format_xhtml)
ext = ".html";
else
ext = ".txt";
/* initialization of global symbols */
inputFileName = outputFileName = 0 ;
sout = 0 ;
docTitle = 0 ;
docHeader = 0 ;
docFooter = 0 ;
docTitle = args_info.title_arg ;
header_fileName = args_info.header_arg ;
footer_fileName = args_info.footer_arg ;
verbose = args_info.verbose_given ;
const string tags_file = args_info.tags_file_arg;
if ( args_info.tab_given > 0 )
tabSpaces = args_info.tab_arg ;
if (header_fileName)
docHeader = read_file (header_fileName);
if (footer_fileName)
docFooter = read_file (footer_fileName);
cssUrl = args_info.css_arg ;
use_css = ( cssUrl != 0 ) ;
entire_doc =
(! args_info.no_doc_given) &&
( args_info.doc_given || (docTitle != 0) || use_css ||
docHeader || docFooter ) ;
string inputFileName;
if (args_info.input_given)
inputFileName = args_info.input_arg ;
string outputFileName;
if ( inputFileName.size() && ! is_cgi && args_info.output_given)
outputFileName = args_info.output_arg ;
bool generate_to_stdout =
(args_info.output_arg &&
strcmp (args_info.output_arg, "STDOUT") == 0);
if ( verbose )
setMessager( new DefaultMessages ) ;
printMessage( PACKAGE ) ;
printMessage( VERSION ) ;
if (args_info.data_dir_given)
data_dir = args_info.data_dir_arg;
if (args_info.check_lang_given) {
cout << "checking " << args_info.check_lang_arg << "... ";
if (LangDefLoader::check_lang_def(data_dir, args_info.check_lang_arg)) {
cout << "OK" << endl;
return(EXIT_SUCCESS);
}
return (EXIT_FAILURE);
}
string lang_map = args_info.lang_map_arg;
langmap = new LangMap(data_dir, lang_map);
if (args_info.lang_list_given) {
cout << "Supported languages (file extensions) and associated language definition files\n\n";
langmap->print();
return (EXIT_SUCCESS);
}
parseTags(data_dir, tags_file) ;
outputbuffer = new OutputBuffer;
if (format_esc)
{
if (use_css)
{
cerr << PACKAGE << ": cannot use css with esc output format" << endl;
return (EXIT_FAILURE);
}
if (args_info.line_number_ref_given)
{
cerr << PACKAGE << ": cannot generate line references in esc output format" << endl;
return (EXIT_FAILURE);
}
generator_factory = new EscGeneratorFactory;
}
else
{
string title;
string doc_header;
string doc_footer;
string css_url;
if (docTitle)
title = docTitle;
if ((! docTitle) && inputFileName.size())
title = inputFileName;
if (docHeader)
doc_header = docHeader;
if (docFooter)
doc_footer = docFooter;
if (cssUrl)
css_url = cssUrl;
if (args_info.line_number_ref_given)
args_info.line_number_given = args_info.line_number_ref_given;
if( use_css )
{
generator_factory =
new CssGeneratorFactory (title,
inputFileName, doc_header,
doc_footer, css_url);
}
else
{
if (format_xhtml && ! args_info.css_given)
generator_factory =
new XHtmlGeneratorFactory
(title,
inputFileName, doc_header,
doc_footer, css_url);
else
generator_factory =
new HtmlGeneratorFactory
(title,
inputFileName, doc_header,
doc_footer, css_url);
}
}
generator_factory->createGenerators ();
docgenerator = generator_factory->createDocGenerator();
if ( is_cgi )
print_cgi_header() ;
// let's start the translation :-)
generate_line_num =
(args_info.line_number_given || args_info.line_number_ref_given);
generate_ref = args_info.line_number_ref_given;
if (tabSpaces)
formatter = new Untabifier (tabSpaces);
else if (args_info.line_number_given)
formatter = new Untabifier(8);
else
formatter = new TextFormatter();
CharTranslator *chartranslator = generator_factory->getCharTranslator();
formatter->setFormatter(chartranslator);
if (args_info.lang_def_arg)
lang_file = args_info.lang_def_arg;
int result = EXIT_SUCCESS;
if (args_info.src_lang_given)
source_language = args_info.src_lang_arg;
// first the --input file
if ( ! args_info.inputs_num ) {
result = processFile(inputFileName, (generate_to_stdout ? "" : outputFileName)) ;
outputbuffer->reset();
}
// let's process other files, if there are any
if ( args_info.inputs_num && !is_cgi ) {
for ( i = 0 ; i < (args_info.inputs_num) ; ++i ) {
result = processFile
( args_info.inputs[i],
(generate_to_stdout ? "" : createOutputFileName (args_info.inputs[i],
args_info.output_dir_arg, ext))) ;
if (result == EXIT_FAILURE)
break;
cerr << "Processed " << args_info.inputs[i] << endl ;
outputbuffer->reset();
}
}
delete outputbuffer;
outputbuffer = 0;
return (result);
}
void
StartApp::print_copyright()
{
int i;
for (i = 1; i <= copyright_text_length; ++i)
cout << copyright_text[i] << endl;;
}
void
StartApp::print_reportbugs()
{
int i;
for (i = 1; i <= reportbugs_text_length; ++i)
cout << reportbugs_text[i] << endl;
}
void
StartApp::print_version()
{
cout << "GNU " << PACKAGE << " " << VERSION << endl;
}
int
StartApp::processFile(const string &inputFileName, const string &outputFileName)
{
FILE *in = 0;
bool deleteOStream = false ;
bool langSpecFound = false;
if ( outputFileName.size() ) {
sout = new ofstream(outputFileName.c_str()) ;
if ( ! (*sout) ) {
cerr << "Error in creating " << outputFileName << " for output" << endl ;
return EXIT_FAILURE ;
}
deleteOStream = true;
}
if (inputFileName.size())
{
unsigned int lines = get_line_count (inputFileName);
line_num_digit = 0;
while (lines)
{
++line_num_digit;
lines /= 10;
}
}
else
line_num_digit = 5;
// if we read from stdin, we can't read the file in advance and
// check how many lines of code it contains. In this case set
// the number of digit for the line number to 5.
/*
* Use default values for any options not provided
*/
if (sout == 0) {
sout = &cout;
}
if (in == 0) {
; /* Well stdin already points to stdin so, .... */
}
if (generate_line_num)
outputgenerator = new LineOutputGenerator(*outputbuffer, *sout, generate_ref);
else
outputgenerator = new OutputGenerator(*outputbuffer, *sout);
if ( entire_doc ) {
docgenerator->set_gen_version (gen_version);
docgenerator->generate_top ();
}
printMessage( "translating source code... ", cerr ) ;
string langfile = lang_file;
if (!langfile.size()) {
// find the language definition file associated to a language
if (source_language.size()) {
langfile = langmap->get_file(source_language);
if (! langfile.size())
{
if (! args_info.failsafe_given)
{
cerr << PACKAGE << ": ";
cerr << "source language " << source_language
<< " not handled" << endl;
return EXIT_FAILURE ;
}
}
else
langSpecFound = true;
} else {
if (! inputFileName.size())
{
if (! args_info.failsafe_given)
{
cerr << PACKAGE << ": ";
cerr << "when using stdin, please specify a source language"
<< endl;
return EXIT_FAILURE ;
}
}
string file_ext = get_file_extension (inputFileName);
if (file_ext == "")
{
if (! args_info.failsafe_given)
{
cerr << PACKAGE << ": ";
cerr << "no file extension; please specify a source language"
<< endl;
return EXIT_FAILURE ;
}
}
langfile = langmap->get_file(file_ext);
if (! langfile.size())
{
if (! args_info.failsafe_given)
{
cerr << PACKAGE << ": ";
cerr << "unknown file extension " << file_ext << endl;
return EXIT_FAILURE ;
}
}
else
langSpecFound = true;
}
}
else
langSpecFound = true;
if (langSpecFound)
{
docgenerator->generate_start_doc ();
const string &i_file_name = get_input_file_name(inputFileName);
const char *input_file_name = (i_file_name.size() ? i_file_name.c_str() : 0);
process_file(input_file_name, formatter, data_dir, langfile);
outputgenerator->generate();
docgenerator->generate_end_doc ();
printMessage( "done !", cerr ) ;
if ( entire_doc ) {
docgenerator->generate_bottom ();
}
}
else // we're in failsafe mode so we simply copy the file to the output
{
istream *input;
if(! inputFileName.size())
input = &cin;
else
input = open_file_istream_or_error(inputFileName);
*sout << input->rdbuf();
if (input != &cin)
delete input;
}
sout->flush ();
if ( deleteOStream )
delete sout ;
delete outputgenerator;
return EXIT_SUCCESS;
}
void
print_cgi_header()
{
printf( "Content-type: text/html\n" ) ;
printf( "\n" ) ;
}