bin/memcp: fix cast
[awesomized/libmemcached] / src / bin / memcp.cc
index e149ef316df876d531b4019596f6a53abd04cedd..eb7151e65a8680155b565cd1a8870cae48e84792 100644 (file)
 #define PROGRAM_VERSION     "1.1"
 
 #include "common/options.hpp"
+#include "common/checks.hpp"
 
+#include <cerrno>
 #include <climits>
 #include <cstdlib>
+#include <libgen.h>
 #include <fstream>
 #include <sstream>
 
 struct memcp_file {
-  enum key {
+  enum class type {
     basename,
     relative,
     absolute
-  } type;
-  enum op {
+  } key;
+  enum class mode {
     SET,
     ADD,
     REPLACE
-  } mode;
-  const char *path;
+  } op;
+  char *path;
   uint32_t flags;
   time_t expire;
 };
 
-static void add_file(std::vector<memcp_file> &files, const client_options &opt, const char *file) {
-  memcp_file::key type = memcp_file::basename;
-  memcp_file::op mode = memcp_file::SET;
+static inline std::string stream2string(const std::istream &istream) {
+  return dynamic_cast<std::ostringstream &&>(std::ostringstream{} << istream.rdbuf()).str();
+}
+
+static memcached_return_t memcp(const client_options &opt, memcached_st &memc, const char *key,
+                  const memcp_file &file) {
+  std::ifstream fstream{};
+  std::istream *istream = check_istream(opt, file.path, fstream);
+
+  if (!istream){
+    return MEMCACHED_ERROR;
+  }
+
+  const char *mode;
+  memcached_return_t rc;
+  auto data = stream2string(*istream);
+  if (file.op == memcp_file::mode::REPLACE) {
+    mode = "replace";
+    rc = memcached_replace(&memc, key, strlen(key), data.c_str(), data.length(),
+        file.expire, file.flags);
+  } else if (file.op == memcp_file::mode::ADD) {
+    mode = "add";
+    rc = memcached_add(&memc, key, strlen(key), data.c_str(), data.length(),
+        file.expire, file.flags);
+  } else {
+    mode = "set";
+    rc = memcached_set(&memc, key, strlen(key), data.c_str(), data.length(),
+        file.expire, file.flags);
+  }
+
+  if (!memcached_success(rc)) {
+    auto error = memcached_last_error(&memc)
+                 ? memcached_last_error_message(&memc)
+                 : memcached_strerror(&memc, rc);
+    std::cerr << "Error occurred during memcached_" << mode <<"('" << key << "'): " << error << "\n";
+  }
+  return rc;
+}
+
+static void add_file(std::vector<memcp_file> &files, const client_options &opt, char *file) {
+  memcp_file::type type = memcp_file::type::basename;
+  memcp_file::mode mode = memcp_file::mode::SET;
   uint32_t flags = 0;
   time_t expire = 0;
 
   if (opt.isset("absolute")) {
-    type = memcp_file::absolute;
+    type = memcp_file::type::absolute;
   } else if (opt.isset("relative")) {
-    type = memcp_file::relative;
+    type = memcp_file::type::relative;
   }
 
   if (opt.isset("replace")) {
-    mode = memcp_file::REPLACE;
+    mode = memcp_file::mode::REPLACE;
   } else if (opt.isset("add")) {
-    mode = memcp_file::ADD;
+    mode = memcp_file::mode::ADD;
   }
 
   if (auto flags_str = opt.argof("flags")) {
@@ -68,17 +110,37 @@ static void add_file(std::vector<memcp_file> &files, const client_options &opt,
   }
 
   if (opt.isset("debug")) {
-    auto mode_str = mode == memcp_file::REPLACE ? "REPLACE" : mode == memcp_file::ADD ? "ADD" : "SET";
+    auto mode_str = mode == memcp_file::mode::REPLACE ? "REPLACE" : mode == memcp_file::mode::ADD ? "ADD" : "SET";
     std::cerr << "Scheduling " << mode_str << " '" << file << "' (expire=" << expire << ", flags=" << flags << ").\n";
   }
 
   files.emplace_back(memcp_file{type, mode, file, flags, expire});
 }
 
+static bool path2key(const client_options &opt, memcp_file &file, char **path) {
+  static char rpath[PATH_MAX + 1];
+  if (file.key == memcp_file::type::absolute) {
+    *path = realpath(file.path, rpath);
+    if (!*path) {
+      if (!opt.isset("quiet")) {
+        perror(file.path);
+      }
+      return false;
+    }
+  } else if (file.key == memcp_file::type::relative) {
+    *path = file.path;
+  } else {
+    *path = basename((file.path));
+  }
+  return true;
+}
+
 int main(int argc, char *argv[]) {
-  memcached_st memc;
   std::vector<memcp_file> files{};
-  client_options opt{PROGRAM_NAME, PROGRAM_VERSION, PROGRAM_DESCRIPTION, "file [file ...]"};
+  client_options opt{PROGRAM_NAME, PROGRAM_VERSION, PROGRAM_DESCRIPTION,
+                     "file [file ...]"
+                     "\n\t\t\t# NOTE: order of flags and positional"
+                     "\n\t\t\t#       arguments matters on GNU systems)"};
 
   opt.add(nullptr, '-', no_argument, "GNU argv extension")
       .parse = [&files](client_options &opt_, client_options::extended_option &ext) {
@@ -110,9 +172,9 @@ int main(int argc, char *argv[]) {
   };
 
   opt.add("udp", 'U', no_argument, "Use UDP.")
-      .apply = [](const client_options &opt, const client_options::extended_option &ext, memcached_st *memc) {
+      .apply = [](const client_options &opt_, const client_options::extended_option &ext, memcached_st *memc) {
     if (MEMCACHED_SUCCESS != memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_USE_UDP, ext.set)) {
-      if (!opt.isset("quiet")) {
+      if (!opt_.isset("quiet")) {
         std::cerr << memcached_last_error_message(memc) << "\n";
       }
       return false;
@@ -135,10 +197,8 @@ int main(int argc, char *argv[]) {
     exit(EXIT_FAILURE);
   }
 
-  if (!memcached_create(&memc)) {
-    if (!opt.isset("quiet")) {
-      std::cerr << "Failed to initialize memcached client.\n";
-    }
+  memcached_st memc;
+  if (!check_memcached(opt, memc)) {
     exit(EXIT_FAILURE);
   }
 
@@ -147,10 +207,7 @@ int main(int argc, char *argv[]) {
   }
 
   if (files.empty()) {
-    if (!*argp) {
-      if (!opt.isset("quiet")) {
-        std::cerr << "No file(s) provided.\n";
-      }
+    if (!check_argp(opt, argp, "No file(s) provided.")) {
       memcached_free(&memc);
       exit(EXIT_FAILURE);
     }
@@ -160,70 +217,27 @@ int main(int argc, char *argv[]) {
   }
 
   auto exit_code = EXIT_SUCCESS;
-  for (const auto &file : files) {
-    auto filename = file.path;
-    std::ifstream filestream{filename, std::ios::in|std::ios::binary};
-
-    if (!filestream) {
-      if (!opt.isset("quiet")) {
-        std::cerr << "Could not open file '" << filename << "'.\n";
-      }
+  for (auto &file : files) {
+    char *path = nullptr;
+    if (!path2key(opt, file, &path)) {
       exit_code = EXIT_FAILURE;
-      // continue;
-    } else {
-      const char *path;
-      char rpath[PATH_MAX+1];
-
-      if (file.type == memcp_file::relative) {
-        path = filename;
-      } else if (file.type == memcp_file::absolute) {
-        path = realpath(filename, rpath);
-        if (!path) {
-          if (!opt.isset("quiet")) {
-            perror(filename);
-          }
-          exit_code = EXIT_FAILURE;
-          continue;
-        }
-      } else {
-        path = basename(filename);
-      }
-
-      std::ostringstream data{};
-      data << filestream.rdbuf();
-
-      memcached_return_t rc;
-      const char *mode;
-      if (file.mode == memcp_file::REPLACE) {
-        mode = "replace";
-        rc = memcached_replace(&memc, path, strlen(path), data.str().c_str(), data.str().length(),
-                               file.expire, file.flags);
-      } else if (file.mode == memcp_file::ADD) {
-        mode = "add";
-        rc = memcached_add(&memc, path, strlen(path), data.str().c_str(), data.str().length(),
-                           file.expire, file.flags);
-      } else {
-        mode = "set";
-        rc = memcached_set(&memc, path, strlen(path), data.str().c_str(), data.str().length(),
-                           file.expire, file.flags);
-      }
-
-      if (MEMCACHED_SUCCESS != rc) {
-        exit_code = EXIT_FAILURE;
-
-        auto error = memcached_last_error(&memc)
-            ? memcached_last_error_message(&memc)
-            : memcached_strerror(&memc, rc);
-        std::cerr << "Error occurred during memcached_" << mode <<"('" << path << "'): " << error << "\n";
-        break;
-      }
+      continue;
+    }
 
+    auto rc = memcp(opt, memc, path, file);
+    if (memcached_success(rc)) {
       if (opt.isset("verbose")) {
-        std::cerr << path << "\n";
+        std::cout << path << "\n";
       }
+    } else {
+      exit_code = EXIT_FAILURE;
     }
   }
 
+  if (!check_buffering(opt, memc)) {
+    exit_code = EXIT_FAILURE;
+  }
+
   memcached_free(&memc);
   exit(exit_code);
 }