// $Id: glade--.cc,v 1.90 2004/05/10 06:33:15 christof Exp $ /* glade--: C++ frontend for glade (Gtk+ User Interface Builder) * Copyright (C) 1998 Christof Petig * Copyright (C) 1999-2002 Adolf Petig GmbH & Co. KG, written by Christof Petig * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include "TagStream.hh" #include "Cxx.hh" #include "Configuration.hh" #include #include #include // for makedir #include #ifndef HAVE_GETOPT_LONG #include "./getopt.h" #else #include #endif #ifndef __MINGW32__ #include #include #endif struct Configuration Configuration; enum longopts { GTKVERSION=0x100, GTKMMVERSION, AUTOCONF, GTK_OSTREAM,FORCE_ACCEL,FORCE_NOACCEL, TEMPL_POSTFIX, OM_STRINGS, OM_CREATE_ENUMS, CASE_CONV, UPPERCASE_ENUMS, MIXEDCASE_DEFINES, OM_NO_CREATE_ENUMS, AUTOMAKE15, EMBED_PICS, LOAD_PICS, BASE_CLASS, SHOW_OPTIONS, NON_VIRTUAL_CALLBACKS, LOOKUP_TABLE, FLAG_GNOME2, LIBGLADE_OPTION, IMAGE_PROVIDER, NOAUTORECONF, AUTORECONF }; const static struct option options[]= { { "directory", required_argument, NULL, 'd' }, { "name", required_argument, NULL, 'm' }, { "version", no_argument, NULL, 'V' }, { "debug", no_argument, NULL, 'g' }, { "samplecode", no_argument, NULL, 's' }, { "barebones", no_argument, NULL, 'r' }, { "gladeonly", no_argument, NULL, 'r' }, { "noautoconf", no_argument, NULL, 'A' }, { "autoconf", no_argument, NULL, AUTOCONF }, { "help", no_argument, NULL, '?' }, { "gtkversion", required_argument, NULL, GTKVERSION }, { "gtkmmversion", required_argument, NULL, GTKMMVERSION }, { "gtkostream", no_argument, NULL, GTK_OSTREAM }, // compatibility with old versions { "widgettable", no_argument, NULL, LOOKUP_TABLE }, { "fulltable", no_argument, NULL, 'w' }, { "libglade", no_argument, NULL, 'l' }, { "libglade-option", no_argument, NULL, LIBGLADE_OPTION }, { "accelerators", no_argument, NULL, FORCE_ACCEL }, { "noaccelerators", no_argument, NULL, FORCE_NOACCEL }, { "template-postfix", required_argument, NULL, TEMPL_POSTFIX }, { "optionmenu-strings", no_argument, NULL, OM_STRINGS }, { "optionmenu-no-create-enums", no_argument,NULL, OM_NO_CREATE_ENUMS }, { "optionmenu-create-enums", no_argument,NULL, OM_CREATE_ENUMS }, { "do-case-conversion", no_argument, NULL, CASE_CONV }, { "uppercase-enums", no_argument, NULL, UPPERCASE_ENUMS }, { "mixedcase-defines", no_argument, NULL, MIXEDCASE_DEFINES }, { "automake-1-5", no_argument, NULL, AUTOMAKE15 }, { "no-autoreconf", no_argument, NULL, NOAUTORECONF }, { "autoreconf", no_argument, NULL, AUTORECONF }, { "embed-images", no_argument, NULL, EMBED_PICS }, { "load-images", no_argument, NULL, LOAD_PICS }, { "baseclass", no_argument, NULL, BASE_CLASS }, { "non-virtual-callbacks", no_argument, NULL, NON_VIRTUAL_CALLBACKS }, { "gnome2", no_argument, NULL, FLAG_GNOME2 }, { "header-suffix", required_argument, NULL, 'h' }, { "source_suffix", required_argument, NULL, 'c' }, { "verbose", no_argument, NULL, 'v' }, { "show-options", no_argument, NULL, SHOW_OPTIONS }, { "image-provider", required_argument, NULL, IMAGE_PROVIDER }, { NULL, 0, NULL, 0 } }; static bool parse_version(const char *arg,Pkg_Version &v, Pkg_Version::Source s=Pkg_Version::Unknown, bool ignore_letters=false) { int mymajor=0,myminor=0,mymicro=0; const char *nextp=arg; if (ignore_letters) { while (*nextp && !isdigit((unsigned char)*nextp)) ++nextp; arg=nextp; } else if (s==Pkg_Version::Gnome_Config) // gnome-config prints 'gnomemm-1.2.2' { nextp=strrchr(arg,'-'); if (nextp) arg=nextp+1; } if (!*arg) return false; mymajor=strtol(arg,const_cast(&nextp),10); if (!*nextp) goto version_ok; if (*nextp!='.' && *nextp!=',') { std::cerr << "error parsing version std::string '" << arg << "\n"; return false; } myminor=strtol(nextp+1,const_cast(&nextp),10); if (!*nextp) goto version_ok; if (*nextp!='.' && *nextp!=',') { if (ignore_letters) goto version_ok; std::cerr << "error parsing version std::string '" << arg << "\n"; return false; } mymicro=strtol(nextp+1,const_cast(&nextp),10); if (ignore_letters || !*nextp || *nextp=='.') // forget about nano version {version_ok: v=Pkg_Version(mymajor,myminor,mymicro,s); return true; } std::cerr << "error parsing version std::string '" << arg << "\n"; return false; } static bool CheckVersion(const std::string &cmd, Pkg_Version &v, Pkg_Version::Source src=Pkg_Version::Unknown, bool ignore_letters=false) { if (v.source==Pkg_Version::Command_Line) return true; char buf[80]; bool result=false; FILE *f=popen(cmd.c_str(),"r"); if (f) { if (fgets(buf,sizeof(buf),f)) { if (!ignore_letters) for (unsigned char *s=(unsigned char*)buf;*s;s++) if (isspace(*s)) { *s=0; break; } // not installed/found if (!strncmp(buf,"Package ",8) && strstr(buf," not ")) result=false; else if (parse_version(buf,v,src,ignore_letters)) result=true; else std::cerr << cmd << ": strange result '" << buf << "'\n"; } pclose(f); } else perror(cmd.c_str()); return result; } static void call_gtkmm_config() { CheckVersion("pkg-config --version",Configuration.pc_version,Pkg_Version::Pkg_Config); if (CheckVersion("automake-1.9 --version",Configuration.automake_version,Pkg_Version::MMVersion,true)) Configuration.automake_name="automake-1.9"; else if (CheckVersion("automake-1.8 --version",Configuration.automake_version,Pkg_Version::MMVersion,true)) Configuration.automake_name="automake-1.8"; else if (CheckVersion("automake-1.7 --version",Configuration.automake_version,Pkg_Version::MMVersion,true)) Configuration.automake_name="automake-1.7"; else if (CheckVersion("automake-1.6 --version",Configuration.automake_version,Pkg_Version::MMVersion,true)) Configuration.automake_name="automake-1.6"; else if (CheckVersion("automake --version",Configuration.automake_version,Pkg_Version::MMVersion,true)) Configuration.automake_name="automake"; else if (CheckVersion("automake-1.5 --version",Configuration.automake_version,Pkg_Version::MMVersion,true)) Configuration.automake_name="automake-1.5"; else if (CheckVersion("automake-1.4 --version",Configuration.automake_version,Pkg_Version::MMVersion,true)) Configuration.automake_name="automake-1.4"; if (CheckVersion("autoconf2.50 --version",Configuration.autoconf_version,Pkg_Version::MMVersion,true)) Configuration.autoconf_name="autoconf2.50"; else if (CheckVersion("autoconf --version",Configuration.autoconf_version,Pkg_Version::MMVersion,true)) Configuration.autoconf_name="autoconf"; else if (CheckVersion("autoconf2.13 --version",Configuration.autoconf_version,Pkg_Version::MMVersion,true)) Configuration.autoconf_name="autoconf2.13"; // if (Configuration.autoconf_version>=Pkg_Version(2,50,0)) // Configuration.use_autoreconf=true; CheckVersion("gettext --version",Configuration.gettext_version,Pkg_Version::MMVersion,true); // Pkgconfig checks (Gnome 2) if (Configuration.gnome2) { if (!!Configuration.pc_version) { CheckVersion("pkg-config --silence-errors --modversion gtk+-2.0",Configuration.gtk_version,Pkg_Version::Pkg_Config); if (!CheckVersion("pkg-config --silence-errors --modversion gtkmm-2.4",Configuration.gtkmm_version,Pkg_Version::Pkg_Config)) CheckVersion("pkg-config --silence-errors --modversion gtkmm-2.0",Configuration.gtkmm_version,Pkg_Version::Pkg_Config); CheckVersion("pkg-config --silence-errors --modversion libgnomemm-2.0",Configuration.libgnomemm_version,Pkg_Version::Pkg_Config); CheckVersion("pkg-config --silence-errors --modversion libgnomeuimm-2.0",Configuration.libgnomeuimm_version,Pkg_Version::Pkg_Config); CheckVersion("pkg-config --silence-errors --modversion libbonobomm-2.0",Configuration.libbonobomm_version,Pkg_Version::Pkg_Config); CheckVersion("pkg-config --silence-errors --modversion libbonobouimm-2.0",Configuration.libbonobouimm_version,Pkg_Version::Pkg_Config); } } else // old script checks { if (!Configuration.pc_version || !CheckVersion("pkg-config --silence-errors --modversion gtk+",Configuration.gtk_version,Pkg_Version::Pkg_Config)) CheckVersion("gtk-config --version",Configuration.gtk_version,Pkg_Version::Gtk_Config); CheckVersion("gtkmm-config --version",Configuration.gtkmm_version,Pkg_Version::Gtkmm_Config); CheckVersion("gnome-config --modversion gnomemm",Configuration.libgnomemm_version,Pkg_Version::Gnome_Config); } } #ifdef __MINGW32__ #define ONLY_UNIX(y,x) #else #define ONLY_UNIX(y,x) y,x #endif static void ApplyProject(const Tag &t) { if (Configuration.main_filename.empty() && t.hasTag("program_name")) Configuration.main_filename=t.getString("program_name","error"); Configuration.source_directory="/"+t.getString("source_directory","src"); if (Configuration.source_directory[1]=='/') { std::cerr << "I can't handle an absolute source directory (" << (Configuration.source_directory.c_str()+1) << ")\n"; exit(2); } Configuration.destination_directory=t.getString("directory","."); if (Configuration.destination_directory.empty()) Configuration.destination_directory="."; if (Configuration.destination_directory!=".") { std::cerr << "I'm confused about the directory to write to, \n" "by default I'm writing relative to the .glade file.\n" "\nPlease report this incident to christof@petig-baender.de for future fixing.\n\n"; Configuration.destination_directory="."; } if (access(Configuration.destination_directory.c_str(),F_OK)) if (mkdir(Configuration.destination_directory.c_str() ONLY_UNIX(,0755))) { perror(Configuration.destination_directory.c_str()); exit(2); } const std::string srcdir(Configuration.destination_directory+Configuration.source_directory); if (access(srcdir.c_str(),F_OK)) if (mkdir(srcdir.c_str() ONLY_UNIX(,0755))) { perror(srcdir.c_str()); exit(2); } Configuration.pixmap_dir=t.getString("pixmaps_directory","pixmaps"); // XXX make pixmaps directory relative to source if ((Configuration.pixmap_dir.empty() || Configuration.pixmap_dir[0]!='/')) // blind guess, but better than nothing { if (Configuration.source_directory!="/" && Configuration.source_directory!="/.") Configuration.pixmap_dir_relative_to_src="../"+Configuration.pixmap_dir; else // src should be current (?) Configuration.pixmap_dir_relative_to_src=Configuration.pixmap_dir; } else Configuration.pixmap_dir_relative_to_src=Configuration.pixmap_dir; if ((Configuration.pixmap_dir.empty() || Configuration.pixmap_dir[0]!='/')) // relative { Configuration.pixmap_dir=Configuration.destination_directory+'/'+Configuration.pixmap_dir; } // Latest glade (1.1.2) doesn't save "gnome+gettext_support" if it is true. Configuration.gnome_support=t.getBool("gnome_support", Configuration.glade2); Configuration.gettext_support=t.getBool("gettext_support", Configuration.glade2); Configuration.widget_names=t.getBool("use_widget_names"); // Configuration.output_main_file=t.getBool("output_main_file"); // ... std::string podir(Configuration.destination_directory+"/po"); if (Configuration.destination_directory.empty()) podir="po"; if (Configuration.gettext_support && access(podir.c_str(),F_OK)) if (mkdir(podir.c_str() ONLY_UNIX(,0755))) { perror(podir.c_str()); exit(2); } Widget::const_contained_iterator::init(); } struct xmloption { const char * const type; const char * const tag; const char * const description; const char * const long_desc; const char * const default_value; const char * const values; }; static void show_options(std::ostream &o) { TagStream ts; ts.setEncoding("UTF-8"); Tag &options=ts.push_back(Tag("glademm-options")); Tag &project=options.push_back(Tag("project")); static const struct xmloption pro_opts[] = { { "string", "program_name", "Name of the executable", 0, 0 ,0 }, { "string", "source_directory", "Source Directory", 0, "src" ,0 }, { "string", "pixmaps_directory", "Image Directory", 0, "pixmaps" ,0 }, { "bool", "gnome_support", "Gnome support", 0, "False" ,0 }, { "bool", "gettext_support", "Gettext support", 0, "False" ,0 }, { "bool", "use_widget_names", "Set widget names", 0, "True" ,0 }, { "bool", "use_widget_names", "Set widget names", 0, "True" ,0 }, // { "bool", "sample_code", "Generate sample code", 0, "False" ,0 }, // { "bool", "no_autoconf", "Generate raw Makefile", 0, "False" ,0 }, { "string", "gtk_version", "Target Gtk+ Version", 0, 0,0 }, { "string", "gtkmm_version", "Target Gtkmm Version", 0, 0,0 }, // { "string", "gnomemm_version", "Target Gnomemm Version", 0, 0 ,0 }, { "bool", "libglade", "Generate libglademm skeleton", 0, "False" ,0 }, { "bool", "accelerators", "Project has accelerators", 0, "False" ,0 }, { "bool", "embed-images", "Embed images in the executable", 0, "True" ,0 }, { "bool", "baseclass", "Use a base class", 0, "False" ,0 }, { "string", "header-suffix", "Header file extension", 0, ".hh" ,0 }, { "string", "source-suffix", "Source file extension", 0, ".cc" ,0 }, { 0,0,0,0,0 ,0 }, }; for (const struct xmloption *i=pro_opts; i->type; ++i) { Tag &t=project.push_back(Tag(i->type)); t.setAttr("tag",i->tag); t.setAttr("description",i->description); if (i->long_desc) t.setAttr("long-description",i->long_desc); if (i->default_value) t.setAttr("default",i->default_value); } Tag &widget=options.push_back(Tag("widget")); static const struct xmloption wdg_opts[] = { { "bool", CXX_SEPERATE_CLASS, "Separate Class", "Put Widget in a separate Class", "False" ,0 }, { "bool", CXX_SEPERATE_FILE, "Separate File", "Put Class in a separate File", "False" ,0 }, { "enum", "cxx_visibility", "Visibility", 0, "private" ,"private|protected|public" }, { 0,0,0,0,0 ,0 }, }; for (const struct xmloption *i=wdg_opts; i->type; ++i) { Tag &t=widget.push_back(Tag(i->type)); t.setAttr("tag",i->tag); t.setAttr("description",i->description); if (i->long_desc) t.setAttr("long-description",i->long_desc); if (i->default_value) t.setAttr("default",i->default_value); if (i->values) t.setAttr("values",i->values); } Tag &signal=options.push_back(Tag("signal")); static const struct xmloption sig_opts[] = { { "string", "data", "data", "Additional arguments to callback", "",0 }, { "string", "data_type", "type(s)", "Types of the arguments", "" ,0 }, { "bool", "connection", "save connection", "Save connection (SigC)", "False" ,0 }, { "bool", "const", "const callback", "Declare this callback as const (can not change class members)", "False" ,0 }, // { "bool", "slot", "slot", "Save slot (SigC)", "False" ,0 }, { 0,0,0,0,0,0 }, }; for (const struct xmloption *i=sig_opts; i->type; ++i) { Tag &t=signal.push_back(Tag(i->type)); t.setAttr("tag",i->tag); t.setAttr("description",i->description); if (i->long_desc) t.setAttr("long-description",i->long_desc); if (i->default_value) t.setAttr("default",i->default_value); } ts.write(o); } static void append_cs_args(const std::string &filename) { try { TagStream ts(filename); Tag &t=ts.getContent(); FOR_EACH_CONST_TAG(i,t) Configuration.custom_signal_args.push_back(*i); } catch (...) {} } static void read_custom_signal_args() { append_cs_args(".glademm-callbacks"); append_cs_args(getenv("HOME")+std::string("/.glademm-callbacks")); append_cs_args(PREFIX "/share/glademm-callbacks"); } int main(int argc,char **argv) { int opt; bool force_gnome2=false; bool force_noaccel=false; int depth=1; for (int i=0;i\tif you don't like 'foo.cc_new'\n" "\t--load-images\tdo not embed images\n" "\t--baseclass\tderive from base class (for class parameters)\n" "\t--libglade\tgenerate code skeleton for a libglade-- application.\n" "\t--libglade-option\tgenerate infrastructure for libglade without using it.\n" "\t--version\tprints 'glademm V"VERSION"'\n"; return 1; } if (argc-optind!=1) goto usage; Configuration.in_filename=argv[optind]; // there should be a way to do this with STL { char buf[10240]; strncpy(buf,argv[optind],sizeof buf); buf[sizeof(buf)-1]=0; char *s=strrchr(buf,'/'); if (s) { Configuration.in_filename=s+1; *s=0; if (*buf) { if (!chdir(buf)) std::cout << "Changed dir to "<Type()!="project") { std::cerr << "Can't find project tag\n"; } else ApplyProject(*t); } else { std::cerr << "Error: strange Tag '" << top.Type() << "'\n"; exit(1); } if (Configuration.debug) top.debug(depth); call_gtkmm_config(); // Apply dependant preferences if (Configuration.gettext_support) { if (Configuration.gtk_version>=Pkg_Version(2,4,0)) Configuration.gettext_source=Configuration::GT_GLIB; else if (Configuration.gnome_support) Configuration.gettext_source=Configuration::GT_GNOME; else Configuration.gettext_source=Configuration::GT_GNU; } if (Configuration.gettext_source==Configuration::GT_GNU && !Configuration.gettext_version) { std::cerr << "gettext not found, disabled\n"; Configuration.gettext_support=false; Configuration.gettext_source=Configuration::GT_NONE; } if (!!Configuration.pc_version) std::cout << "Found pkg-config version " << Configuration.pc_version << '\n'; std::cout << "Generating code for gtk " << Configuration.gtk_version << " (" << Configuration.gtk_version.getSource() << "), gtkmm " << Configuration.gtkmm_version << " (" << Configuration.gtkmm_version.getSource() << ')'; if (!!Configuration.libgnomemm_version) { std::cout << ", "; if (!Configuration.gnome_support) std::cout << '['; std::cout << "gnomemm " << Configuration.libgnomemm_version << " (" << Configuration.libgnomemm_version.getSource() << ')'; if (Configuration.Gnome2()) { if (!!Configuration.libgnomeuimm_version) std::cout << "\n\tgnomeuimm " << Configuration.libgnomeuimm_version << " (" << Configuration.libgnomeuimm_version.getSource() << ')'; if (!!Configuration.libbonobomm_version) std::cout << " bonobomm " << Configuration.libbonobomm_version << " (" << Configuration.libbonobomm_version.getSource() << ')'; if (!!Configuration.libbonobouimm_version) std::cout << " bonobouimm " << Configuration.libbonobouimm_version << " (" << Configuration.libbonobouimm_version.getSource() << ')'; } if (!Configuration.gnome_support) std::cout << ']'; } std::cout << '\n'; if (!Configuration.no_autoconf) { std::cout << "Using " << Configuration.autoconf_name << ' ' << Configuration.autoconf_version << ", " << Configuration.automake_name << ' ' << Configuration.automake_version; if (Configuration.gettext_source==Configuration::GT_GNU) { std::cout << ", gettext " << Configuration.gettext_version; } else if (Configuration.gettext_source==Configuration::GT_GNOME) { std::cout << ", gnome's gettext"; } else if (Configuration.gettext_source==Configuration::GT_GLIB) { std::cout << ", glib's gettext"; } std::cout << '\n'; } if (Configuration.gnome_support && !Configuration.Gtkmm1()) { std::cerr << "Gnome 2.x support is unmaintained - expect problems\n"; } #if 0 if (Configuration.gettext_support && !Configuration.gnome_support && Configuration.Gtkmm1()) { std::cout << "Gettext support is not yet implemented without gnome.\n" "Is there any standard way of accessing gettext?\n" "Disabling gettext for now.\n"; Configuration.gettext_support=false; } #endif #ifndef __MINGW32__ {struct passwd *pwd=getpwuid(getuid()); struct utsname uts; if (uname(&uts)) { strcpy(uts.nodename,"(unknown)"); #ifdef HAS_DOMAINNAME strcpy(uts.domainname,"(unknown)"); #endif } Configuration.author_email=std::string(pwd?pwd->pw_name:"(unknown)") + "@" + uts.nodename #ifdef HAS_DOMAINNAME + "." + uts.domainname #endif ; #ifdef HAS_REAL_NAME Configuration.author_name= pwd->HAS_REAL_NAME; #endif } #endif // now the generated project rejects to compile // if (Configuration.Gtkmm2()) // std::cout << "WARNING: THIS PROGRAM WILL CRASH IF COMPILED WITH G++ 2.9x!!!\n"; if (force_noaccel && Configuration.has_accelerators) Configuration.has_accelerators=false; Cxx *cxx=new Cxx(&top); cxx->WriteTags(); if (Configuration.only_private_widgets) std::cerr << "WARNING: All your widgets are declared as private members, so I made them all\n" "\tpublic. Use \"visibilty\" to tell which widgets you need to access.\n"; delete cxx; return 0; } catch (std::exception &e) { std::cerr << "Error "<< e.what()<<" loading .glade file, exiting.\n"; exit(1); } } // ok, strictly this does not belong here ... std::ostream &operator<<(std::ostream &o, const Pkg_Version &v) { return o << v.mymajor << '.' << v.myminor << '.' << v.mymicro; } std::ostream &operator<<(std::ostream &o, const Pkg_Version::Source s) { if (s==Pkg_Version::Not_Available) o << "n.a."; else if (s==Pkg_Version::Unknown) o << "unknown"; else if (s==Pkg_Version::Glademm_Compile_Time) o << "compiled in"; else if (s==Pkg_Version::Command_Line) o << "specified"; else if (s==Pkg_Version::Gtk_Config) o << "gtk-config"; else if (s==Pkg_Version::Gtkmm_Config) o << "gtkmm-config"; else if (s==Pkg_Version::Gnome_Config) o << "gnome-config"; else if (s==Pkg_Version::Pkg_Config) o << "pkg-config"; else o << ""; return o; }