/* G-Cows - scripting language for creation of web sites Copyright (C) 2002, 2003, 2004, 2005, 2006 Andrea Sozzi This file is part of G-Cows. G-Cows 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, or (at your option) any later version. G-Cows 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "cows_options.H" #include // #include #include #include #include #include //#include #if HAVE_GETOPT_LONG # include #else /* ! HAVE_GETOPT_LONG */ # include #endif #include "error.H" #include "file_utils.H" using namespace std; Cows_opt::Cows_opt (int argc, char *argv[]) { int parsed_opt; int exit_mode, verbosity; bool set_never_exit = false, set_exit_on_warning = false; bool set_silent = false, set_verbose = false; string input, output; string dir = string (get_w_dir ()) + "/"; #if HAVE_GETOPT_LONG static struct option const options[] = { { "accessibility", no_argument, NULL, 'A' }, { "brief", no_argument, NULL, 'b' }, { "define", required_argument, NULL, 'D' }, { "root-dir", required_argument, NULL, 'd' }, { "fatal-warnings", no_argument, NULL, 'E' }, { "help", no_argument, NULL, 'h' }, { "ignore-errors", no_argument, NULL, 'i' }, { "noext-error", no_argument, NULL, 'N' }, { "noext-warning", no_argument, NULL, 'n' }, { "parents", no_argument, NULL, 'p' }, { "quiet", no_argument, NULL, 'q' }, { "report", optional_argument, NULL, 'r' }, { "silent", no_argument, NULL, 's' }, { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, {NULL, 0, NULL, 0} }; #endif Msg::inst()->set_program_name (argv[0]); program_name = argv[0]; // Set some default values; will be overwritten by command line options exit_mode = Msg::exit_on_error; verbosity = Msg::standard; set_opt (Cows_opt::root_dir, "./"); // Parse command line options /* If ouput is a relative file name it must be converted to absolute in order to create directories if needed. Conversion can't be postponed to dump_buffer () since we need the starting directory */ #if HAVE_GETOPT_LONG while ((parsed_opt = getopt_long (argc, argv, "AD:d:r::qsvbpEihV", options, NULL)) != -1) #else /* ! HAVE_GETOPT_LONG */ while ((parsed_opt = getopt (argc, argv, "AD:d:r::qsvbpEihV")) != -1) #endif { switch (parsed_opt) { case 0: break; case 'A': accessibility (); break; case 'b': Msg::inst()->set_brief (true); break; case 'D': add_opt (Cows_opt::define, optarg); break; case 'N': set_opt (Cows_opt::noext, "error"); break; case 'n': set_opt (Cows_opt::noext, "warning"); break; case 'p': set_opt (Cows_opt::parents, "yes"); break; case 'd': set_opt (Cows_opt::root_dir, add_slash (optarg)); break; case 'E': set_exit_on_warning = true; exit_mode = Msg::exit_on_warning; break; case 'h': usage (EXIT_SUCCESS); break; case 'i': set_never_exit = true; exit_mode = Msg::never_exit; break; case 'q': case 's': verbosity = Msg::silent; set_silent = true; break; case 'r': set_opt (Cows_opt::report, "yes"); if (optarg) { set_opt (Cows_opt::report_file, optarg); // ??? set_opt (Cows_opt::report_file, to_absolute (optarg)); } break; case 'v': verbosity = Msg::verbose; set_verbose = true; break; case 'V': version (); break; default: usage (EXIT_FAILURE); } } if (set_verbose && set_silent) Msg::inst()->fatal ("incompatible options `verbose' and `silent'"); if (set_never_exit && set_exit_on_warning) Msg::inst()->fatal ("incompatible options `fatal-warnings' and `ignore-errors'"); Msg::inst()->set_verbosity (verbosity); Msg::inst()->set_exit_mode (exit_mode); if (argc - optind != 2) usage (EXIT_FAILURE); input = string (argv[optind]); output = string (argv[optind+1]); struct stat stat_in; struct stat stat_out; if ((input != "-") && (output != "-")) { if (stat (input.c_str(), &stat_in)) Msg::inst()->sys_error ("unable to get infos about " + input, input); else { if (! stat (output.c_str(), &stat_out)) { if ( (stat_in.st_ino == stat_out.st_ino) && (stat_in.st_dev == stat_out.st_dev) ) Msg::inst()->fatal ("`" + input + "' and `" + output + "' are the same file"); } } } // Open input file if needed if (input != "-" ) { input_file = fopen (input.c_str (), "r"); if (input_file == NULL) Msg::inst()->sys_fatal ("can't open input file " + input, input); } set_opt (Cows_opt::input, input); if (output != "-") { set_opt (Cows_opt::output, opt_file_name (output)); set_opt (Cows_opt::output_abs, to_absolute (output)); // Not optimized } else { set_opt (Cows_opt::output, output); set_opt (Cows_opt::output_abs, output); // Not optimized name } } Cows_opt::~Cows_opt () { if (get_opt (Cows_opt::input) != "-") if (input_file) fclose (input_file); } /* User can initialize variables from command line: cows --define var1=foo --define var2=cws ... Return the next initializaton string or "" if no (more) strings are available */ string Cows_opt::get_next_var () { pair opt_iters = equal_range (define); static iterator begin_var = opt_iters.first; static iterator end_var = opt_iters.second; if (begin_var == end_var) return ""; else return (*(begin_var++)).second; } void Cows_opt::dump_output (const char *p2output) { if (! p2output) return; if (get_opt (Cows_opt::output_abs) == "-") cout << p2output; else { string output = get_opt (Cows_opt::output_abs); ofstream *output_stream = new ofstream ( output.c_str() ); if (! *output_stream) { if (get_opt (Cows_opt::parents) != "yes") Msg::inst()->sys_fatal ("can't open output file " + output, output); else { /* Ok, we failed in opening the output file AND --create-dir option was used; so we see if the target directory exist and, if not, we create it. Then, we retry opening the file. */ int slash_pos = 0; string tmp_string = output; struct stat *entry_full_info; string_vector dirs; string_iter iter; while ((slash_pos = tmp_string.rfind ('/'))) { entry_full_info = new struct stat; tmp_string = tmp_string.substr (0, slash_pos); if (stat (tmp_string.c_str (), entry_full_info) && (errno == ENOENT)) dirs.push_back (tmp_string); } reverse (dirs.begin (), dirs.end ()); for (iter = dirs.begin (); iter != dirs.end (); iter++) if (mkdir ((*iter).c_str (), S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) Msg::inst()->sys_fatal ("can't create directory " + *iter, *iter); output_stream = new ofstream ( output.c_str() ); if ( ! *output_stream ) Msg::inst()->sys_fatal ("can't open output file " + output, output); } } * output_stream << p2output; output_stream->close (); delete (output_stream); } } void Cows_opt::dump_report (string in, string out, int warnings, int errors) { if (get_opt (Cows_opt::report) == "yes") { std::ostringstream report_message; string report = get_opt (Cows_opt::report_file); report_message << in << " > " << out << " [ " << Msg::inst()->get_n_warnings () << " warnings - " << Msg::inst()->get_n_errors () << " errors ]\n"; if (report == "") cerr << report_message.str (); else { ofstream report_stream (report.c_str(), ios::app); if ( ! report_stream ) Msg::inst()->sys_fatal ("can't open report file " + report, report); report_stream << report_message.rdbuf (); report_stream.close (); } } } /* Display a short usage message and exit */ void Cows_opt::usage (int status) { if (status != 0) { cerr << "Usage: " << program_name << " [OPTIONS] INPUT-FILE OUTPUT-FILE\n"; cerr << "Try `" << program_name << " --help' for more information.\n"; } else { cout << "Usage: " << program_name << " [OPTIONS] INPUT-FILE OUTPUT-FILE\n\ Scripting language for creation of web sites.\n\n\ -A, --accessibility Display informations about accessibility issues\n\ related to Cows\n\ -b, --brief Display output in a compact format. The amount\n\ of messages won't change, they will only be\n\ shorter. Visually impaired users relying on a\n\ speech version of shell's output may find this\n\ flag useful since large amounts of output can\n\ slow down work. \n\ -D, --define=DEFINITION Define a variable before running Cows. \n\ Cows will treat this variable as if it were \n\ defined at the beginning of input-file. \n\ DEFINITION can be a standard Cows variable \n\ assignment (VARIABLE=VALUE) or simply a \n\ variable name; in this case variable will be \n\ assigned an empty string. \n\ -d, --root-dir=DIRECTORY Set site's root directory; Cows needs this \n\ information in order to provide some features \n\ related to link adjustment. If not provided, \n\ Cows will use the launching directory.\n\ This default behaviour is the right one if you \n\ use Cows-mkgen and Make to manage your site. \n\ -E, --fatal-warnings Stop execution after first warning (default \n\ behavior is to give an advice and continue \n\ running).\n\ -h, --help Display help message and exit. \n\ -i, --ignore-errors Keep running after errors.\n\ -N, --noext-error Don't execute external scripts or commands; \n\ raise an error instead \n\ -n, --noext-warning Don't execute external scripts or commands; \n\ raise a warning instead \n\ -p, --parents Make parent directories as needed. \n\ -q, --quiet Same as `--silent' \n\ -r, --report[=FILE] Produce a report of what have been done \n\ and append it to FILE. If you don't provide \n\ a file name, report is printed to stderr.\n\n\ -s, --silent Don't print informational messages. \n\ -V, --version Display the version number of Cows and exit.\n\ -v, --verbose Produce a more verbose description. \n\n\ Cows: n. pl. pl. of cow.\n\ domesticated mammals of the genus Bos, often raised for meat and dairy\n\ products; it's obviously a bad habit, since killing living beings for\n\ eating or wearing is __WRONG__\n\ Cows: (also) scripting language for creation of web sites on Unix and\n\ Linux systems. \n\n\ Cows parses text files containing additional scripts; its output is \n\ represented by a verbatim copy of text file with scripts replaced by their\n\ outputs.\n\n\ Cows is often used in combination with Cows-mkgen (cows-mkgen --help for\n\ further informations); both Cows and Cows-mkgen come with the package \n\ `G-Cows'. See http://www.g-cows.org/ for documentation and latest release.\n\n\ Please report bugs to .\n\ "; } exit (status); } /* Display G-Cows version and exit */ void Cows_opt::version () { cout << "Cows version " << VERSION << "\n\ Copyright (C) 2002, 2003, 2004, 2005, 2006 Andrea Sozzi \n\ Cows comes with ABSOLUTELY NO WARRANTY; not even for MERCHANTABILITY\n\ or FITNESS FOR A PARTICULAR PURPOSE.\n\ You may redistribute copies of Cows under the terms of the \n\ GNU General Public License. \n\ For more information about these matters, see the files named COPYING. \n\ "; exit (EXIT_SUCCESS); } void Cows_opt::accessibility () { cout << "\ Cows is a command line tool and its output is not visually formatted\n\ with ASCII characters so accessibility problems should be minimal.\n\ The --brief option forces Cows to display output in a compact format.\n\ amount of messages won't change, they will only be shorter. Visually\n\ impaired users relying on a speech version of shell's output may find this\n\ flag useful since large amounts of output can slow down work. \n\ "; exit (EXIT_SUCCESS); }