changeset 6043:199f15a8d1fc

[project @ 2006-10-09 19:49:03 by jwe]
author jwe
date Mon, 09 Oct 2006 19:49:04 +0000
parents 40be03213eb5
children 12fd61d549ba
files ChangeLog Makeconf.in configure.in src/ChangeLog src/DLD-FUNCTIONS/urlwrite.cc src/Makefile.in src/oct-conf.h.in src/toplev.cc
diffstat 8 files changed, 488 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Oct 09 16:44:08 2006 +0000
+++ b/ChangeLog	Mon Oct 09 19:49:04 2006 +0000
@@ -1,3 +1,10 @@
+2006-10-09  John W. Eaton  <jwe@octave.org>
+
+	* Makeconf.in (CURL_LIBS, do-subst-config-vals):
+	Substitute CURL_LIBS.
+
+	* configure.in: Check for libcurl.
+
 2006-10-04  John W. Eaton  <jwe@octave.org>
 
 	* Makeconf.in (library_path_var): Substitute value from configure.
--- a/Makeconf.in	Mon Oct 09 16:44:08 2006 +0000
+++ b/Makeconf.in	Mon Oct 09 19:49:04 2006 +0000
@@ -196,6 +196,7 @@
 BLAS_LIBS = @BLAS_LIBS@
 FFTW_LIBS = @FFTW_LIBS@
 GLPK_LIBS = @GLPK_LIBS@
+CURL_LIBS = @CURL_LIBS@
 AMD_LIBS = @AMD_LIBS@
 CAMD_LIBS = @CAMD_LIBS@
 UMFPACK_LIBS = @UMFPACK_LIBS@
@@ -433,6 +434,7 @@
   -e "s|%OCTAVE_CONF_CFLAGS%|\"${CFLAGS}\"|" \
   -e "s|%OCTAVE_CONF_CPICFLAG%|\"${CPICFLAG}\"|" \
   -e "s|%OCTAVE_CONF_CPPFLAGS%|\"${CPPFLAGS}\"|" \
+  -e "s|%OCTAVE_CONF_CURL_LIBS%|\"${CURL_LIBS}\"|" \
   -e "s|%OCTAVE_CONF_CXX%|\"${CXX}\"|" \
   -e "s|%OCTAVE_CONF_CXXCPP%|\"${CXXCPP}\"|" \
   -e "s|%OCTAVE_CONF_CXXFLAGS%|\"${CXXFLAGS}\"|" \
--- a/configure.in	Mon Oct 09 16:44:08 2006 +0000
+++ b/configure.in	Mon Oct 09 19:49:04 2006 +0000
@@ -29,7 +29,7 @@
 EXTERN_CXXFLAGS="$CXXFLAGS"
 
 AC_INIT
-AC_REVISION($Revision: 1.523 $)
+AC_REVISION($Revision: 1.524 $)
 AC_PREREQ(2.57)
 AC_CONFIG_SRCDIR([src/octave.cc])
 AC_CONFIG_HEADER(config.h)
@@ -545,6 +545,28 @@
 fi
 AC_SUBST(GLPK_LIBS)
 
+# Checks for CURL header and library.
+
+AC_ARG_WITH(curl,
+  [AS_HELP_STRING([--without-curl], [don't use CURL])],
+  with_curl=$withval, with_curl=yes)
+
+curl_lib=
+if test "$with_curl" = yes; then
+  curl_lib="curl"
+elif test "$with_curl" != no; then
+  curl_lib="$with_curl"
+fi
+
+CURL_LIBS=
+if test -n "$curl_lib"; then
+  AC_CHECK_LIB($curl_lib, curl_global_init, [
+    AC_CHECK_HEADERS(curl/curl.h, [
+      CURL_LIBS="-l$curl_lib"
+      AC_DEFINE(HAVE_CURL, 1, [Define if CURL is available.])])])
+fi
+AC_SUBST(CURL_LIBS)
+
 OCTAVE_IEEE754_DATA_FORMAT
 
 # ----------------------------------------------------------------------
@@ -1798,6 +1820,7 @@
   CHOLMOD libraries:    $CHOLMOD_LIBS
   CXSPARSE libraries:   $CXSPARSE_LIBS
   HDF5 libraries:       $HDF5_LIBS
+  CURL libraries:       $CURL_LIBS
   REGEX libraries:      $REGEX_LIBS
   LIBS:                 $LIBS
   Default pager:        $DEFAULT_PAGER
--- a/src/ChangeLog	Mon Oct 09 16:44:08 2006 +0000
+++ b/src/ChangeLog	Mon Oct 09 19:49:04 2006 +0000
@@ -1,3 +1,12 @@
+2006-10-09  John W. Eaton  <jwe@octave.org>
+
+	* oct-conf.h.in (OCTAVE_CONF_CURL_LIBS): Substitute.
+	* toplev.cc (octave_config_info): Add CURL_LIBS to the list.
+
+2006-10-09  Alexander Barth  <abarth@marine.usf.edu>
+
+	* DLD-FUNCTIONS/urlwrite.cc: New file providing urlwrite and urlread.
+
 2006-10-09  John W. Eaton  <jwe@octave.org>
 
 	* pt-mat.cc (tree_matrix::dup): Append new elements to new matrix.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/DLD-FUNCTIONS/urlwrite.cc	Mon Oct 09 19:49:04 2006 +0000
@@ -0,0 +1,436 @@
+// urlwrite and urlread, a curl front-end for octave
+/*
+
+Copyright (C) 2006 Alexander Barth
+
+This file is part of Octave.
+
+Octave 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.
+
+Octave 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 Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+*/
+
+// Author: Alexander Barth <abarth@marine.usf.edu>
+// Adapted-By: jwe
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string>
+#include <fstream>
+#include <iomanip>
+
+#include "oct-env.h"
+
+#include "defun-dld.h"
+#include "error.h"
+#include "oct-obj.h"
+#include "ov-cell.h"
+#include "pager.h"
+
+#if defined (HAVE_CURL)
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+// Write callback function for curl.
+
+int
+write_data (void *buffer, size_t size, size_t nmemb, void *streamp)
+{
+  // *stream is actually an ostream object.
+  std::ostream& stream = *(static_cast<std::ostream*> (streamp));
+  stream.write (static_cast<const char*> (buffer), size*nmemb);
+  return (stream.fail () ? 0 : size * nmemb);
+}
+
+// Progress callback function for curl.
+
+int
+progress_func (const char *url, double dltotal, double dlnow,
+	       double /*ultotal*/, double /*ulnow*/)
+{
+  // macro that picks up Ctrl-C signalling
+  OCTAVE_QUIT;
+
+#if !defined (URL_QUITE_DOWNLOAD)
+  if (dltotal != 0)
+    {
+      // Is the carriage return character "\r" portable?
+      octave_stdout << "\r" << url << ": "
+		    << std::fixed << std::setw(5) << std::setprecision(1)
+		    << dlnow*100.0/dltotal << " %";
+
+      octave_stdout.flush ();
+    }
+#endif
+
+  return 0;
+}
+
+// Form the query string based on param.
+
+std::string
+form_query_string (CURL *curl, const Cell& param)
+{
+  std::ostringstream query;
+
+  for (int i = 0; i < param.numel (); i += 2)
+    {
+      std::string name = param(i).string_value ();
+      std::string text = param(i+1).string_value ();
+
+      // Encode strings.
+      char *enc_name = curl_easy_escape (curl, name.c_str (), name.length ());
+      char *enc_text = curl_easy_escape (curl, text.c_str (), text.length ());
+
+      query << enc_name << "=" << enc_text;
+
+      curl_free (enc_name);
+      curl_free (enc_text);
+
+      if (i < param.numel()-1)
+	query << "&";
+    }
+
+  query.flush ();
+
+  return query.str ();
+}
+
+// curl front-end
+
+CURLcode
+urlget (const std::string& url, const std::string& method,
+	const Cell& param, std::ostream& stream)
+{
+  CURL *curl;
+
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+
+  curl = curl_easy_init();
+
+  if (! curl)
+    return CURLE_FAILED_INIT;
+
+  // handle paramters of GET or POST request
+
+  std::string query_string = form_query_string (curl,param);
+  //octave_stdout << "query_string " << query_string << std::endl;
+
+  if (method == "get")
+    {
+      query_string = url + "?" + query_string;
+      curl_easy_setopt (curl, CURLOPT_URL, query_string.c_str ());
+    }
+  else if (method == "post")
+    {
+      curl_easy_setopt (curl, CURLOPT_URL, url.c_str ());
+      curl_easy_setopt (curl, CURLOPT_POSTFIELDS, query_string.c_str ());
+    }
+  else
+    {
+      curl_easy_setopt (curl, CURLOPT_URL,url.c_str());
+    }
+
+  // Define our callback to get called when there's data to be written.
+  curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, write_data);
+
+  // Set a pointer to our struct to pass to the callback.
+  curl_easy_setopt (curl, CURLOPT_WRITEDATA, static_cast<void*> (&stream));
+
+  curl_easy_setopt (curl, CURLOPT_NOPROGRESS, false);
+  curl_easy_setopt (curl, CURLOPT_PROGRESSFUNCTION, progress_func);
+  curl_easy_setopt (curl, CURLOPT_PROGRESSDATA, url.c_str ());
+  curl_easy_setopt (curl, CURLOPT_FAILONERROR, true);
+
+  // Switch on full protocol/debug output
+  // curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
+
+  CURLcode res = curl_easy_perform(curl);
+
+#if !defined (URL_QUITE_DOWNLOAD)
+  if (res == CURLE_OK)
+    {
+      // download is complete
+      progress_func (url.c_str (), 1, 1, 0, 0);
+      // new line after progress_func
+      octave_stdout << std::endl;
+    }
+#endif
+
+  // always cleanup
+  curl_easy_cleanup (curl);
+
+  curl_global_cleanup ();
+
+  return res;
+}
+
+#endif
+
+DEFUN_DLD (urlwrite, args, nargout,
+  "-*- texinfo -*-\n\
+@deftypefn {Loadable Function} {} urlwrite (@var{URL}, @var{localfile})\n\
+@deftypefnx {Loadable Function} {@var{f} =} urlwrite (@var{url}, @var{localfile})\n\
+@deftypefnx {Loadable Function} {[@var{f}, @var{success}] =} urlwrite (@var{url}, @var{localfile})\n\
+@deftypefnx {Loadable Function} {[@var{f}, @var{success}, @var{message}] =} urlwrite (@var{url}, @var{localfile})\n\
+Download a remote file specified by its @var{URL} and save it as\n\
+@var{localfile}.  For example,\n\
+\n\
+@example\n\
+urlwrite ('ftp://ftp.octave.org/pub/octave/README', 'README.txt');\n\
+@end example\n\
+\n\
+The full path of the downloaded file is returned in @var{f}.  The\n\
+variable @var{success} is 1 if the download was successful,\n\
+otherwise it is 0 in which case @var{message} contains an error\n\
+message.  If no output argument is specified and if an error occurs,\n\
+then the error is signaled through octave's error handling mechanism.\n\
+\n\
+This function uses libcurl.  Curl supports, among others, the HTTP,\n\
+FTP and FILE protocols.  Username and password may be specified in\n\
+the URL, for example:\n\
+\n\
+@example\n\
+urlwrite ('http://username:password@@example.com/file.txt', 'file.txt');\n\
+@end example\n\
+\n\
+GET and POST requests can be specified by @var{method} and @var{param}.\n\
+The parameter @var{method} is either 'get' or 'post' and @var{param} is a\n\
+cell array of parameter and value pairs.  For example:\n\
+\n\
+@example\n\
+urlwrite ('http://www.google.com/search', 'search.html', 'get', @{'query', 'octave'@});\n\
+@end example\n\
+@seealso{urlread}\n\
+@end deftypefn")
+{
+  octave_value_list retval;
+
+#if defined (HAVE_CURL)
+
+  int nargin = args.length ();
+
+  // verify arguments
+  if (nargin != 2 && nargin != 4)
+    {
+      print_usage ();
+      return retval;
+    }
+
+  std::string url = args(0).string_value();
+
+  if (error_state)
+    {
+      error ("urlwrite: url must be a character string");
+      return retval;
+    }
+
+  // name to store the file if download is succesful
+  std::string filename = args(1).string_value();
+
+  if (error_state)
+    {
+      error ("urlwrite: localfile must be a character string");
+      return retval;
+    }
+
+  std::string method;
+  Cell param; // empty cell array
+
+  if (nargin == 4)
+    {
+      method = args(2).string_value();
+
+      if (error_state)
+        {
+          error ("urlwrite: method can only be \"get\" or \"post\"");
+          return retval;
+        }
+
+      if (method != "get" && method != "post")
+	{
+	  error ("urlwrite: method can only be \"get\" or \"post\"");
+	  return retval;
+	}
+
+      param = args(3).cell_value();
+
+      if (error_state)
+	{
+	  error ("urlwrite: parameters for get and post requests must be given as a cell");
+	  return retval;
+	}
+
+
+      if (param.numel () % 2 == 1 )
+	{
+	  error ("urlwrite: number of elements in param must be even");
+	  return retval;
+	}
+    }
+
+  // create and open file stream
+
+  std::ofstream stream (filename.c_str(), std::ios::out | std::ios::binary);
+
+  if (! stream.is_open ())
+    {
+      error ("urlwrite: unable to open file");
+      return retval;
+    }
+
+  CURLcode res = urlget (url, method, param, stream);
+
+  // close the local file
+  stream.close ();
+
+  if (nargout > 0)
+    {
+      // FIXME: urlwrite should return full file path
+      retval(0) = octave_env::make_absolute (filename, octave_env::getcwd ());
+      //      retval(0) = filename;
+      retval(1) = res == CURLE_OK;
+      // return empty string if no error occured
+      retval(2) = std::string (res == CURLE_OK ? "" : curl_easy_strerror (res));
+    }
+
+  if (nargout < 2 & res != CURLE_OK)
+    error ("urlwrite: curl: %s", curl_easy_strerror (res));
+
+#else
+  error ("urlwrite: not available in this version of Octave");
+#endif
+
+  return retval;
+}
+
+DEFUN_DLD (urlread, args, nargout,
+  "-*- texinfo -*-\n\
+@deftypefn {Loadable Function} {@var{s} =} urlread(@var{url})\n\
+@deftypefnx {Loadable Function} {[@var{s}, @var{success}] =} urlread (@var{url})\n\
+@deftypefnx {Loadable Function} {[@var{s}, @var{success}, @var{message}] =} urlread(@var{url})\n\
+@deftypefnx {Loadable Function} {[...] =} urlread (@var{url}, @var{method}, @var{param})\n\
+Download a remote file specified by its @var{URL} and return its content\n\
+in string @var{s}.  For example,\n\
+\n\
+@example\n\
+s = urlread ('ftp://ftp.octave.org/pub/octave/README');\n\
+@end example\n\
+\n\
+The variable @var{success} is 1 if the download was successful,\n\
+otherwise it is 0 in which case @var{message} contains an error\n\
+message.  If no output argument is specified and if an error occurs,\n\
+then the error is signaled through octave's error handling mechanism.\n\
+\n\
+This function uses libcurl.  Curl supports, among others, the HTTP,\n\
+FTP and FILE protocols.  Username and password may be specified in the\n\
+URL.  For example,\n\
+\n\
+@example\n\
+s = urlread ('http://username:password@@example.com/file.txt');\n\
+@end example\n\
+\n\
+GET and POST requests can be specified by @var{method} and @var{param}.\n\
+The parameter @var{method} is either 'get' or 'post' and @var{param} is a\n\
+cell array of parameter and value pairs.  For example,\n\
+\n\
+@example\n\
+s = urlread ('http://www.google.com/search', 'get', @{'query', 'octave'@});\n\
+@end example\n\
+@seealso{urlwrite}\n\
+@end deftypefn")
+{
+  // octave's return value
+  octave_value_list retval;
+
+#if defined (HAVE_CURL)
+
+  int nargin = args.length ();
+
+  // verify arguments
+  if (nargin != 1  && nargin != 3)
+    {
+      print_usage ();
+      return retval;
+    }
+
+  std::string url = args(0).string_value();
+
+  if (error_state)
+    {
+      error ("urlread: url must be a character string");
+      return retval;
+    }
+
+  std::string method;
+  Cell param; // empty cell array
+
+  if (nargin == 3)
+    {
+      method = args(1).string_value();
+
+      if (error_state)
+	{
+	  error ("urlread: method can only be \"get\" or \"post\"");
+	  return retval;
+	}
+
+      if (method != "get" && method != "post")
+	{
+	  error ("urlread: method can only be \"get\" or \"post\"");
+	  return retval;
+	}
+
+      param = args(2).cell_value();
+
+      if (error_state)
+	{
+	  error ("urlread: parameters for get and post requests must be given as a cell");
+	  return retval;
+	}
+
+      if (param.numel () % 2 == 1 )
+	{
+	  error ("urlread: number of elements in param must be even");
+	  return retval;
+	}
+    }
+
+  // string stream for output
+  std::ostringstream stream;
+
+  CURLcode res = urlget (url, method, param, stream);
+
+  if (nargout > 0)
+    {
+      retval(0) = stream.str ();
+      retval(1) = res == CURLE_OK;
+      // return empty string if no error occured
+      retval(2) = std::string (res == CURLE_OK ? "" : curl_easy_strerror (res));
+    }
+
+  if (nargout < 2 & res != CURLE_OK)
+    error ("urlread: curl: %s", curl_easy_strerror (res));
+
+#else
+  error ("urlread: not available in this version of Octave");
+#endif
+
+  return retval;
+}
--- a/src/Makefile.in	Mon Oct 09 16:44:08 2006 +0000
+++ b/src/Makefile.in	Mon Oct 09 19:49:04 2006 +0000
@@ -52,7 +52,7 @@
 	lu.cc luinc.cc matrix_type.cc minmax.cc pinv.cc qr.cc \
 	quad.cc qz.cc rand.cc regexp.cc schur.cc sort.cc sparse.cc \
 	spchol.cc spdet.cc spfind.cc spkron.cc splu.cc spparms.cc spqr.cc \
-	sqrtm.cc svd.cc syl.cc time.cc \
+	sqrtm.cc svd.cc syl.cc time.cc urlwrite.cc \
 	__gnuplot_raw__.l __glpk__.cc __pchip_deriv__.cc __qp__.cc
 
 DLD_SRC := $(addprefix DLD-FUNCTIONS/, $(DLD_XSRC))
@@ -573,11 +573,15 @@
   ifdef CXXPICFLAG
     regexp.oct : pic/regexp.o octave$(EXEEXT)
 	  $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(REGEX_LIBS)
+    urlwrite.oct : pic/urlwrite.o octave$(EXEEXT)
+	  $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(CURL_LIBS)
     __glpk__.oct : pic/__glpk__.o octave$(EXEEXT)
 	  $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(GLPK_LIBS)
   else
     regexp.oct : regexp.o octave$(EXEEXT)
 	  $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(REGEX_LIBS)
+    urlwrite.oct : urlwrite.o octave$(EXEEXT)
+	  $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(CURL_LIBS)
     __glpk__.oct : __glpk__.o octave$(EXEEXT)
 	  $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(GLPK_LIBS)
   endif
--- a/src/oct-conf.h.in	Mon Oct 09 16:44:08 2006 +0000
+++ b/src/oct-conf.h.in	Mon Oct 09 19:49:04 2006 +0000
@@ -73,6 +73,10 @@
 #define OCTAVE_CONF_CPPFLAGS %OCTAVE_CONF_CPPFLAGS%
 #endif
 
+#ifndef OCTAVE_CONF_CURL_LIBS
+#define OCTAVE_CONF_CURL_LIBS %OCTAVE_CONF_CURL_LIBS%
+#endif
+
 #ifndef OCTAVE_CONF_CXXCPP
 #define OCTAVE_CONF_CXXCPP %OCTAVE_CONF_CXXCPP%
 #endif
--- a/src/toplev.cc	Mon Oct 09 16:44:08 2006 +0000
+++ b/src/toplev.cc	Mon Oct 09 19:49:04 2006 +0000
@@ -722,6 +722,7 @@
       "CFLAGS", OCTAVE_CONF_CFLAGS,
       "CPICFLAG", OCTAVE_CONF_CPICFLAG,
       "CPPFLAGS", OCTAVE_CONF_CPPFLAGS,
+      "CURL_LIBS", OCTAVE_CONF_CURL_LIBS,
       "CXX", OCTAVE_CONF_CXX,
       "CXXCPP", OCTAVE_CONF_CXXCPP,
       "CXXFLAGS", OCTAVE_CONF_CXXFLAGS,