/* * 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" ) ; }