/* 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 #include #include #include #include "common.H" #include "error.H" #include "file_utils.H" #include "cows-mkgen_options.H" #include "language.H" #define PROGRAM_NAME "cows-mkgen" #define AUTHORS "Andrea Sozzi" using namespace std; extern FILE *yyin; static Mkgen_opt *opts; Deps_tree *tree; extern int yyparse (void); void parse_function (string root_dir = ""); int main (int argc, char *argv[]) { setlocale (LC_ALL, ""); opts = new Mkgen_opt (argc, argv); tree = new Deps_tree (opts->get_opt (Mkgen_opt::o_target_extension)); if (opts->get_opt (Mkgen_opt::o_fast_mode) == "y") tree->set_fast_deps (); string dist_noup_target = "\n\ndist-noupdate:\n\t"; string options = "prefix = " + opts->get_opt (Mkgen_opt::o_prefix) + "\n" + "\n__cows_OPTS = "+opts->get_opt (Mkgen_opt::o_cows_option) + "\nmain_OPTS = " + opts->get_opt (Mkgen_opt::o_branch_option) + "\n"; // Scan main site parse_function (); // Scan branches while (opts->next_branch ()) { options += (opts->get_opt (Mkgen_opt::o_branch_id) + " = " + opts->get_opt (Mkgen_opt::o_branch_option) + "\n"); parse_function (); } /* File checks are done within Mkgen_opt class constructor so we can safely assume that output file is correctly open at this stage */ string root_and_output = opts->get_opt (Mkgen_opt::o_root_dir) + opts->get_opt (Mkgen_opt::o_branch_root) + opts->get_opt (Mkgen_opt::o_output); if ( (opts->get_opt (Mkgen_opt::o_prefix) == "./") && (opts->get_opt (Mkgen_opt::o_root_dir) == "./") ) { string site_dir = (opts->get_opt (Mkgen_opt::o_prefix) == "./") ? opts->get_opt (Mkgen_opt::o_root_dir) : opts->get_opt (Mkgen_opt::o_prefix); site_dir = opt_file_name (to_absolute (site_dir)); int last_slash = site_dir.rfind ("/", site_dir.length () - 2); site_dir = site_dir.substr (last_slash + 1, site_dir.length () - last_slash - 2); dist_noup_target += ("cd ../ && \\\n\ttar chozf " + site_dir + "/" + site_dir + ".tar.gz \\\n\t-X " + site_dir + "/" + opts->get_opt (Mkgen_opt::o_output) + ".sources " + site_dir + " && \\\n\tcd " + site_dir); string out = opts->get_opt (Mkgen_opt::o_output); tree->write_sources_list (out + "\n" + out + "~\n" + out + ".cm\n" + out + ".cm~\n" + out + ".sources\n" + out + ".sources~\n" + out + ".add\n" + out + ".add~\n" + site_dir + ".tar.gz\n"); opts->create_src_file (tree->get_sources_list ()); } else { dist_noup_target += "@echo \"NO ARCHIVE CREATED. This feature is only \ enabled when Cows-mkgen is run without neither --prefix nor --root-dir \ option\""; } string file_list = tree->get_file_list (); if (file_list == "") { Msg::inst()->log ("No source file found .. creating empty makefile", "Empty makefile created"); opts->create_empty_makefile (); } else { string targets = "TARGETS = " + file_list; ifstream in ((opts->get_opt (Mkgen_opt::o_output) + ".add").c_str ()); ostringstream add_mkf_stream; if (in) { add_mkf_stream << in.rdbuf (); } string always_target = ""; string all_target = "all: $(TARGETS)"; string clean_target = "\n\nclean:\n\trm -f $(TARGETS) "; string phony_target = "\n\n.PHONY: all clean dist dist-noupdate sitedist"; if (tree->get_always_list () != "") { all_target += " always"; always_target = "always: " + tree->get_always_cmds (); clean_target += tree->get_always_list (); phony_target += " always"; } string output_name = opts->get_opt (Mkgen_opt::o_output); ofstream output_stream (output_name.c_str()); if ( ! output_stream ) Msg::inst()->fatal ("Can't open output file " + output_name, output_name); output_stream << "# Generated automatically from " << opts->get_opt (Mkgen_opt::o_output) << ".cm by cows-mkgen " << VERSION << "\n# Copyright (C) 2002, 2003, 2004, 2005, 2006 Andrea Sozzi\n" << "# This makefile is free software; you have unlimited\n" << "# permission to copy and/or distribute it, with or without\n" << "# modifications, as long as this notice is preserved.\n\n" << "# This makefile is distributed in the hope that it will be \n" << "# useful, but WITHOUT ANY WARRANTY, to the extent permitted\n" << "# by law; without even the implied warranty of \n" << "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n\n" << options << "\n\n" << targets << "\n" << all_target << "\n\n" << (tree->get_output ()).str () << "\n\n" << add_mkf_stream.str() << always_target << clean_target << dist_noup_target << "\n\ndist: all dist-noupdate\n\nsitedist: dist-noupdate\n\n" << phony_target << endl; output_stream.close (); } return (EXIT_SUCCESS); } void parse_function (string root_dir) { // directories containing input and output files static string input_dir; static string output_dir; static int transl_point = 0; string saved_input_dir = input_dir; string saved_output_dir = output_dir; DIR *dir_stream; struct dirent *dir_entry; struct stat *dir_entry_stat = new struct stat; char *saved_absolute_dir = get_w_dir (); string start_from = (root_dir == "") ? opts->get_opt (Mkgen_opt::o_root_dir) + opts->get_opt (Mkgen_opt::o_branch_root) : root_dir; if (input_dir == "") { /* This is the first call for parse_function (). We get here once for each branch */ input_dir = opts->get_opt (Mkgen_opt::o_root_dir) + opts->get_opt (Mkgen_opt::o_branch_root); if (opts->get_opt (Mkgen_opt::o_prefix) == "") { // No prefix: output files will be created within source directory output_dir = opts->get_opt (Mkgen_opt::o_root_dir) + opts->get_opt (Mkgen_opt::o_branch_prefix); } else { // Prefix: output files will be created in a different directory /* prefix is now defined as a Makefile variable output_dir = opts->get_opt (Mkgen_opt::o_prefix) + opts->get_opt (Mkgen_opt::o_branch_prefix); */ string mkf_prefix = string("$(prefix)"); output_dir = mkf_prefix + opts->get_opt (Mkgen_opt::o_branch_prefix); /* We evaluate prefix length: later, translation file names will be created inserting a translation label here. */ /* prefix is now defined as a Makefile variable transl_point = (opts->get_opt (Mkgen_opt::o_prefix)).length(); */ transl_point = mkf_prefix.length(); /* Feature: an option could allow to set translation point after branch prefix ('acc/IT/about/index.html' instead of 'IT/acc/about/index.html') */ } } else { output_dir += (string (root_dir) + "/"); input_dir += (string (root_dir) + "/"); } // Move to site's root directory and open it if (chdir (start_from.c_str ())) Msg::inst()->sys_fatal ("can't change directory to " + start_from, start_from); dir_stream = opendir ("./"); if (! dir_stream) Msg::inst()->fatal ("can't open directory " + input_dir, input_dir ); // Scan site's root directory while ((dir_entry = readdir (dir_stream))) { string entry = string (dir_entry->d_name); if ( (entry == ".") || (entry == "..") ) continue; // skip current dir and parent if ( stat (dir_entry->d_name, dir_entry_stat) ) { Msg::inst()->sys_error ("unable to get infos about file " + entry, entry); continue; // skip this entry } if (S_ISDIR (dir_entry_stat->st_mode) ) { // Found directory // Check for `nomkgen' string nomkgen_fname = entry + "/nomkgen"; FILE *nomkgen_file = fopen (nomkgen_fname.c_str (), "r"); if (nomkgen_file) { struct stat *nomk_stat = new struct stat; if ( stat (nomkgen_fname.c_str (), nomk_stat) ) { Msg::inst()->sys_error ("while checking for " + nomkgen_fname); continue; // skip this entry } fclose (nomkgen_file); if (! S_ISREG (nomk_stat->st_mode)) { //`nomkgen' is not a file: recursive call parse_function (entry); } else { // Directory name must be optimized otherwise tar screws up tree->write_sources_list (opt_file_name (input_dir + entry) + "\n"); } } else { // No file `nomkgen': recursive call bool no_output = false; string nooutput_fname = entry + "/nooutput"; FILE *nooutput_file = fopen (nooutput_fname.c_str (), "r"); if (nooutput_file) { struct stat *noout_stat = new struct stat; if ( stat (nooutput_fname.c_str (), noout_stat) ) { Msg::inst()->sys_error ("while checking for " + nooutput_fname); continue; // skip this entry } fclose (nooutput_file); if (S_ISREG (noout_stat->st_mode)) { //Directory name must be optimized tree->write_sources_list (opt_file_name (input_dir + entry) + "\n"); no_output = true; } } if (no_output) tree->enter_noout_dir_mode (); parse_function (entry); if (no_output) tree->leave_noout_dir_mode (); } } else { // found file .. let's check extension unsigned int dot_pos = entry.rfind ('.'); if ( ( dot_pos != string::npos)) { // OK, there is an extension string src_wo_ext = entry.substr (0, dot_pos + 1); string extension = entry.substr (dot_pos+1, entry.length ()); if (extension == opts->get_opt (Mkgen_opt::o_source_extension)) { // This is a cows file.. looping on translations and parsing for (String_iter i = (opts->get_transl ()).begin (); i != (opts->get_transl ()).end (); i++) { string input_file = opt_file_name (input_dir + entry); string output_file; string transl_opts; string try_open = entry; if (*i != "") { output_file = opt_file_name (output_dir.substr (0,transl_point) + *i + "/" + output_dir.substr (transl_point) + src_wo_ext); transl_opts = " -p -D_LANG=" + *i + " "; try_open += ("." + *i); Msg::inst()->opt ("Checking for " + input_file + "." + *i); } else { Msg::inst()->opt ("Checking for " + input_file); output_file = opt_file_name (output_dir + src_wo_ext); } tree->set_up (input_dir + entry); bool missing_transl = false; if ((yyin = fopen (try_open.c_str (), "r")) == NULL) { if (*i == "") { Msg::inst()->sys_error ("can't open file " + try_open, try_open); continue; // skip this entry } else { missing_transl = true; Msg::inst()->opt ("Missing Translation " + try_open); transl_opts += "-D_REVERT "; } } if (*i == "") { Msg::inst()->set_parsed_file (input_dir + entry); tree->set_input_file (input_file); tree->set_output_file (output_file); yyparse (); Msg::inst()->erase_buffer (); } else { if (! missing_transl) input_file += ("." + *i); } string ext = tree->get_and_delete_custom_ext (); if (ext != "") { output_file += ext; } else { output_file += opts->get_opt (Mkgen_opt::o_target_extension); } if (! missing_transl) fclose (yyin); string command = "\n\tcows $(__cows_OPTS) $(" + opts->get_opt (Mkgen_opt::o_branch_id) + ") " + transl_opts + input_file + " " + output_file; tree->write_output (output_file + ":\t" + input_file); if (tree->is_deps ()) { tree->dump_cache (); tree->write_output (command + "\n\n"); tree->write_always (command); } else if (tree->is_fast_deps ()) { tree->write_output (command + "\n\n"); tree->write_always (command); if (tree->get_cache_size () > 0) { // Solo se c'e' almeno una dipendenza tree->write_output (input_file + ":\t"); tree->dump_cache (); } tree->write_output ("\n\n"); } else { Msg::inst()->sys_fatal ("unknown mode"); } string input_file_wo_dir = strip_dir (input_file); tree->write_sources_list (input_file + "\n" + input_file + "~\n"); if (tree->is_silent ()) tree->leave_silent_mode (); else if (! tree->is_noout_dir_mode ()) tree->write_file_list (output_file + "\\\n"); } tree->clear_cache (); } tree->unset_always (); } } } if (closedir (dir_stream)) Msg::inst()->sys_error ("can't close directory " + root_dir, root_dir); input_dir = saved_input_dir; output_dir = saved_output_dir; if (chdir (saved_absolute_dir)) Msg::inst()->sys_fatal ("can't change directory to " + string (saved_absolute_dir), string (saved_absolute_dir)); }