Mercurial > hg > octave-terminal
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 +++ b/ChangeLog @@ -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 +++ b/Makeconf.in @@ -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 +++ b/configure.in @@ -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 +++ b/src/ChangeLog @@ -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.
new file mode 100644 --- /dev/null +++ b/src/DLD-FUNCTIONS/urlwrite.cc @@ -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 +++ b/src/Makefile.in @@ -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 +++ b/src/oct-conf.h.in @@ -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