Expand ~ when present in directory path

pdfium_test currently isn't expanding ~ in paths that are passed in
for directories, which is causing commands like this pdfium_test
--font-dir=~/Fonts to fail. This CL adds in performing sh style
expansion on the ~ character for --font-dir and --bin-dir.

This change depends on POSIX wordexp being available, so guarding the
code with checks for Linux || OSX, since those are the only platforms
that we build for that are POSIX complient in this regard.

BUG=pdfium:1027

Change-Id: I05d518dfa71d95c3b0cfd1f4b382e0a6f4a0f515
Reviewed-on: https://pdfium-review.googlesource.com/28611
Reviewed-by: dsinclair <dsinclair@chromium.org>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc
index b0268d0..3dcd831 100644
--- a/samples/pdfium_test.cc
+++ b/samples/pdfium_test.cc
@@ -34,6 +34,7 @@
 #include "samples/pdfium_test_write_helper.h"
 #include "testing/test_support.h"
 #include "third_party/base/logging.h"
+#include "third_party/base/optional.h"
 
 #ifdef _WIN32
 #include <io.h>
@@ -56,6 +57,16 @@
 #define R_OK 4
 #endif
 
+// wordexp is a POSIX function that is only available on OSX and non-Android
+// Linux platforms.
+#if defined(__APPLE__) || (defined(__linux__) && !defined(__ANDROID__))
+#define WORDEXP_AVAILABLE
+#endif
+
+#ifdef WORDEXP_AVAILABLE
+#include <wordexp.h>
+#endif  // WORDEXP_AVAILABLE
+
 enum OutputFormat {
   OUTPUT_NONE,
   OUTPUT_STRUCTURE,
@@ -113,6 +124,23 @@
   int last_page;
 };
 
+Optional<std::string> ExpandDirectoryPath(const std::string& path) {
+#if defined(WORDEXP_AVAILABLE)
+  wordexp_t expansion;
+  if (wordexp(path.c_str(), &expansion, 0) != 0 || expansion.we_wordc < 1) {
+    wordfree(&expansion);
+    return {};
+  }
+  // Need to contruct the return value before hand, since wordfree will
+  // deallocate |expansion|.
+  Optional<std::string> ret_val = {expansion.we_wordv[0]};
+  wordfree(&expansion);
+  return ret_val;
+#else
+  return {path};
+#endif  // WORDEXP_AVAILABLE
+}
+
 struct FPDF_FORMFILLINFO_PDFiumTest : public FPDF_FORMFILLINFO {
   // Hold a map of the currently loaded pages in order to avoid them
   // to get loaded twice.
@@ -300,7 +328,14 @@
         fprintf(stderr, "Duplicate --font-dir argument\n");
         return false;
       }
-      options->font_directory = cur_arg.substr(11);
+      std::string path = cur_arg.substr(11);
+      auto expanded_path = ExpandDirectoryPath(path);
+      if (!expanded_path) {
+        fprintf(stderr, "Failed to expand --font-dir, %s\n", path.c_str());
+        return false;
+      }
+      options->font_directory = expanded_path.value();
+
 #ifdef _WIN32
     } else if (cur_arg == "--emf") {
       if (options->output_format != OUTPUT_NONE) {
@@ -336,7 +371,13 @@
         fprintf(stderr, "Duplicate --bin-dir argument\n");
         return false;
       }
-      options->bin_directory = cur_arg.substr(10);
+      std::string path = cur_arg.substr(10);
+      auto expanded_path = ExpandDirectoryPath(path);
+      if (!expanded_path) {
+        fprintf(stderr, "Failed to expand --bin-dir, %s\n", path.c_str());
+        return false;
+      }
+      options->bin_directory = expanded_path.value();
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 #endif  // PDF_ENABLE_V8