First try of zypper "shell" command.
authorMartin Vidner <mvidner@suse.cz>
Wed, 1 Nov 2006 16:14:48 +0000 (16:14 +0000)
committerMartin Vidner <mvidner@suse.cz>
Wed, 1 Nov 2006 16:14:48 +0000 (16:14 +0000)
Split option parsing to a separate file.

package/zypper.changes
src/Makefile.am
src/zypper-getopt.cc [new file with mode: 0644]
src/zypper-getopt.h [new file with mode: 0644]
src/zypper.cc

index 7e17a27..ca5563c 100644 (file)
@@ -1,4 +1,9 @@
 -------------------------------------------------------------------
+Wed Nov  1 17:14:23 CET 2006 - mvidner@suse.cz
+
+- First try of zypper "shell" command.
+
+-------------------------------------------------------------------
 Tue Oct 31 21:41:56 CET 2006 - mvidner@suse.cz
 
 - Fixed endless loop if stdin not available (#216210).
index ad5ff22..5ac587c 100644 (file)
@@ -52,6 +52,8 @@ zypper_SOURCES =      zypper.cc zmart-sources.cc zmart-misc.cc \
        zypper-search.cc \
        zypper-info.h \
        zypper-info.cc \
+       zypper-getopt.h \
+       zypper-getopt.cc \
        zmart.h
 zypper_LDADD = $(ZYPP_LIBS) -lboost_regex
 
diff --git a/src/zypper-getopt.cc b/src/zypper-getopt.cc
new file mode 100644 (file)
index 0000000..32b4df5
--- /dev/null
@@ -0,0 +1,100 @@
+#include "zypper-getopt.h"
+#include <iostream>
+#include <zypp/base/String.h>
+using namespace std;
+
+string longopts2optstring (const struct option *longopts) {
+  // + - do not permute, stop at the 1st nonoption, which is the command
+  // : - return : to indicate missing arg, not ?
+  string optstring = "+:";
+  for (; longopts && longopts->name; ++longopts) {
+    if (!longopts->flag && longopts->val) {
+      optstring += (char) longopts->val;
+      if (longopts->has_arg == required_argument)
+       optstring += ':';
+      else if (longopts->has_arg == optional_argument)
+       optstring += "::";
+    }
+  }
+  //cerr << optstring << endl;
+  return optstring;
+}
+
+typedef map<int,const char *> short2long_t;
+
+short2long_t make_short2long (const struct option *longopts) {
+  short2long_t result;
+  for (; longopts && longopts->name; ++longopts) {
+    if (!longopts->flag && longopts->val) {
+      result[longopts->val] = longopts->name;
+    }
+  }
+  return result;
+}
+
+// longopts.flag must be NULL
+parsed_opts parse_options (int argc, char **argv,
+                          const struct option *longopts) {
+  parsed_opts result;
+  opterr = 0;                  // we report errors on our own
+  int optc;
+  string optstring = longopts2optstring (longopts);
+  short2long_t short2long = make_short2long (longopts);
+
+  while (1) {
+    int option_index = 0;
+    optc = getopt_long (argc, argv, optstring.c_str (),
+                       longopts, &option_index);
+    if (optc == -1)
+      break;                   // options done
+
+    switch (optc) {
+    case '?':
+      result["_unknown"].push_back("");
+      cerr << "Unknown option " << argv[optind - 1] << endl;
+      break;
+    case ':':
+      cerr << "Missing argument for " << argv[optind - 1] << endl;
+      break;
+    default:
+      const char *mapidx = optc? short2long[optc] : longopts[option_index].name;
+
+      // creates if not there
+      list<string>& value = result[mapidx];
+      if (optarg)
+       value.push_back (optarg);
+      else
+       value.push_back ("");
+      break;
+    }
+  }
+  return result;
+}
+
+
+Args::Args (const std::string& s)
+  : _argv(NULL) {
+  OIter oit (this);
+  zypp::str::split (s, oit);
+}
+
+void Args::clear_argv () {
+  if (_argv != NULL) {
+    for (char **pp = _argv; *pp != NULL; ++pp)
+      free (*pp);
+    delete[] _argv;
+    _argv = NULL;
+  }
+}
+void Args::make_argv () {
+  int c = _args.size ();
+  _argv = new char* [c + 1];
+  char **pp = _argv;
+  for (int i = 0; i < c; ++i) {
+    *pp++ = strdup (_args[i].c_str());
+  }
+  *pp = NULL;
+}
+// Local Variables:
+// c-basic-offset: 2
+// End:
diff --git a/src/zypper-getopt.h b/src/zypper-getopt.h
new file mode 100644 (file)
index 0000000..859bcf8
--- /dev/null
@@ -0,0 +1,81 @@
+/*-----------------------------------------------------------*- c++ -*-\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+
+
+#ifndef ZYPPER_GETOPT_H_
+#define ZYPPER_GETOPT_H_
+
+#include <map>
+#include <list>
+#include <vector>
+#include <string>
+
+#include <getopt.h>
+
+typedef std::map<std::string, std::list<std::string> > parsed_opts;
+
+// longopts.flag must be NULL
+parsed_opts parse_options (int argc, char **argv,
+                          const struct option *longopts);
+
+
+//! Parse a single string to an array of char* usable for getopt_long.
+class Args {
+public:
+  Args (const std::string& s);
+
+  ~Args () {
+    clear_argv ();
+  }
+
+  int argc () const {
+    return _args.size ();
+  }
+  char ** argv () {
+    clear_argv ();
+    make_argv ();
+    return _argv;
+  }
+
+private:
+  // output iterator for split
+  class OIter {
+    Args * _dest;              //!< the destination object
+  public:
+    OIter (Args * dest): _dest (dest) {}
+
+    OIter& operator ++ () {
+      return *this;            // do nothing, operator = is enough
+    }
+    OIter& operator * () {
+      return *this;     // the iterator works as the proxy object too
+    }
+    OIter& operator = (const std::string& s) {
+      _dest->_args.push_back (s); // do the real work
+      return *this;
+    }
+  };
+  
+  friend class OIter;
+
+  void clear_argv ();
+  void make_argv ();
+
+  // for parsing
+  std::vector<std::string> _args;
+  // holds the argv style args
+  char ** _argv;
+};
+
+
+#endif /*ZYPPER_GETOPT_H_*/
+// Local Variables:
+// mode: c++
+// c-basic-offset: 2
+// End:
index 01a338b..de5d97f 100644 (file)
@@ -12,7 +12,6 @@
 #include <iterator>
 
 #include <unistd.h>
-#include <getopt.h>
 
 #include "zmart.h"
 #include "zmart-sources.h"
@@ -25,6 +24,7 @@
 #include "zypper-tabulator.h"
 #include "zypper-search.h"
 #include "zypper-info.h"
+#include "zypper-getopt.h"
 
 using namespace std;
 using namespace boost;
@@ -43,76 +43,6 @@ MediaCallbacks media_callbacks;
 KeyRingCallbacks keyring_callbacks;
 DigestCallbacks digest_callbacks;
 
-typedef map<string, list<string> > parsed_opts;
-
-string longopts2optstring (const struct option *longopts) {
-  // + - do not permute, stop at the 1st nonoption, which is the command
-  // : - return : to indicate missing arg, not ?
-  string optstring = "+:";
-  for (; longopts && longopts->name; ++longopts) {
-    if (!longopts->flag && longopts->val) {
-      optstring += (char) longopts->val;
-      if (longopts->has_arg == required_argument)
-       optstring += ':';
-      else if (longopts->has_arg == optional_argument)
-       optstring += "::";
-    }
-  }
-  //cerr << optstring << endl;
-  return optstring;
-}
-
-typedef map<int,const char *> short2long_t;
-
-short2long_t make_short2long (const struct option *longopts) {
-  short2long_t result;
-  for (; longopts && longopts->name; ++longopts) {
-    if (!longopts->flag && longopts->val) {
-      result[longopts->val] = longopts->name;
-    }
-  }
-  return result;
-}
-
-// longopts.flag must be NULL
-parsed_opts parse_options (int argc, char **argv,
-                          const struct option *longopts) {
-  parsed_opts result;
-  opterr = 0;                  // we report errors on our own
-  int optc;
-  string optstring = longopts2optstring (longopts);
-  short2long_t short2long = make_short2long (longopts);
-
-  while (1) {
-    int option_index = 0;
-    optc = getopt_long (argc, argv, optstring.c_str (),
-                       longopts, &option_index);
-    if (optc == -1)
-      break;                   // options done
-
-    switch (optc) {
-    case '?':
-      result["_unknown"].push_back("");
-      cerr << "Unknown option " << argv[optind - 1] << endl;
-      break;
-    case ':':
-      cerr << "Missing argument for " << argv[optind - 1] << endl;
-      break;
-    default:
-      const char *mapidx = optc? short2long[optc] : longopts[option_index].name;
-
-      // creates if not there
-      list<string>& value = result[mapidx];
-      if (optarg)
-       value.push_back (optarg);
-      else
-       value.push_back ("");
-      break;
-    }
-  }
-  return result;
-}
-
 static struct option global_options[] = {
   {"help",     no_argument, 0, 'h'},
   {"verbose",  no_argument, 0, 'v'},
@@ -140,23 +70,35 @@ Url make_url (const string & url_s) {
   return u;
 }
 
-int main(int argc, char **argv)
+string help_commands = _(
+  "  Commands:\n"
+  "\thelp\t\t\tHelp\n"
+  "\tinstall, in\t\tInstall packages or resolvables\n"
+  "\tremove, rm\t\tRemove packages or resolvables\n"
+  "\tsearch, se\t\tSearch for packages matching a pattern\n"
+  "\tservice-list, sl\tList services aka installation sources\n"
+  "\tservice-add, sa\t\tAdd a new service\n"
+  "\tservice-delete, sd\tDelete a service\n"
+  "\tservice-rename, sr\tRename a service\n"
+  "\trefresh, ref\t\tRefresh all installation sources\n"
+  "\tpatch-check, pchk\tCheck for patches\n"
+  "\tpatches, pch\t\tList patches\n"
+  "\tlist-updates, lu\tList updates\n"
+  "\tupdate, up\t\tUpdate packages\n"
+  "\tinfo, if\t\tShow full info for packages\n"
+  "");
+
+// global options
+parsed_opts gopts;
+bool help = false;
+
+// parses global options, returns the command
+string process_globals(int argc, char **argv)
 {
-  struct Bye {
-    ~Bye() {
-      cerr_vv << "Exiting main()" << endl;
-    }
-  } say_goodbye __attribute__ ((__unused__));
-
-  const char *logfile = getenv("ZYPP_LOGFILE");
-  if (logfile == NULL)
-    logfile = ZYPP_CHECKPATCHES_LOG;
-  zypp::base::LogControl::instance().logfile( logfile );
-
-  bool help = false;
-  parsed_opts gopts = parse_options (argc, argv, global_options);
+  // global options
+  gopts = parse_options (argc, argv, global_options);
   if (gopts.count("_unknown"))
-    return 1;
+    return "_unknown";
 
   if (gopts.count("rug-compatible"))
     gSettings.is_rug_compatible = true;
@@ -221,34 +163,27 @@ int main(int argc, char **argv)
   }
 
   if (command.empty()) {
-    cerr_vv << "No command" <<endl;
-    //command = "help";
+    if (help) {
+      cerr << help_global_options << help_commands;
+    }
+    else {
+      cerr << "Try -h for help" << endl;
+    }
   }
+
   cerr_vv << "COMMAND: " << command << endl;
+  return command;
+}
 
+/// process one command from the OS shell or the zypper shell
+int one_command(const string& command, int argc, char **argv)
+{
   // === command-specific options ===
 
   struct option no_options = {0, 0, 0, 0};
   struct option *specific_options = &no_options;
   string specific_help;
 
-  string help_commands = _("  Commands:\n"
-      "\thelp\t\t\tHelp\n"
-      "\tinstall, in\t\tInstall packages or resolvables\n"
-      "\tremove, rm\t\tRemove packages or resolvables\n"
-      "\tsearch, se\t\tSearch for packages matching a pattern\n"
-      "\tservice-list, sl\tList services aka installation sources\n"
-      "\tservice-add, sa\t\tAdd a new service\n"
-      "\tservice-delete, sd\tDelete a service\n"
-      "\tservice-rename, sr\tRename a service\n"
-      "\trefresh, ref\t\tRefresh all installation sources\n"
-      "\tpatch-check, pchk\tCheck for patches\n"
-      "\tpatches, pch\t\tList patches\n"
-      "\tlist-updates, lu\tList updates\n"
-      "\tupdate, up\t\tUpdate packages\n"
-      "\tinfo, if\t\tShow full info for packages\n"
-      "");
-
   string help_global_source_options = "  Source options:\n"
       "\t--disable-system-sources, -D\t\tDon't read the system sources\n"
       "\t--source, -S\t\tRead additional source\n"
@@ -438,16 +373,6 @@ int main(int argc, char **argv)
   
   // === execute command ===
 
-  if (command.empty()) {
-    if (help) {
-      cerr << help_global_options << help_commands;
-    }
-    else {
-      cerr << "Try -h for help" << endl;
-    }
-    return 0;
-  }
-
   if (command == "moo") {
     cout << "   \\\\\\\\\\\n  \\\\\\\\\\\\\\__o\n__\\\\\\\\\\\\\\'/_" << endl;
     return 0;
@@ -834,6 +759,56 @@ int main(int argc, char **argv)
 
   return 0;
 }
+
+void command_shell ()
+{
+  bool loop = true;
+  while (loop) {
+    // read a line
+    cerr << "zypper> " << flush;
+    string line = zypp::str::getline (cin);
+    cerr_vv << "Got: " << line << endl;
+    // reset optind etc
+    optind = 0;
+    // split it up and create sh_argc, sh_argv
+    Args args(line);
+    int sh_argc = args.argc ();
+    char **sh_argv = args.argv ();
+
+    string command = sh_argv[0]? sh_argv[0]: "";
+    // TODO check empty command
+
+    if (command == "exit")
+      loop = false;
+    else
+      one_command (command, sh_argc, sh_argv);
+  }
+}
+
+int main(int argc, char **argv)
+{
+  struct Bye {
+    ~Bye() {
+      cerr_vv << "Exiting main()" << endl;
+    }
+  } say_goodbye __attribute__ ((__unused__));
+
+  // logging
+  const char *logfile = getenv("ZYPP_LOGFILE");
+  if (logfile == NULL)
+    logfile = ZYPP_CHECKPATCHES_LOG;
+  zypp::base::LogControl::instance().logfile( logfile );
+  
+  // parse global options and the command
+  string command = process_globals (argc, argv);
+  int ret = 0;
+  if (command == "shell")
+    command_shell ();
+  else
+    ret = one_command (command, argc, argv);
+
+  return ret;
+}
 // Local Variables:
 // c-basic-offset: 2
 // End: