summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2012-12-11 23:31:45 +0100
committerDaniel Stenberg <daniel@haxx.se>2012-12-11 23:31:45 +0100
commit50d7397ea54df79e403649d1e37d002eb52d268f (patch)
tree6b6eed95d3d4b69cd26e0b2377fa934d5ea99c09 /src
parenta3d6368c690b943e92082951e8c5fc3ef2d76c12 (diff)
parent4deb52831a071bc83cefb4871764281a5c32f902 (diff)
downloadcurl-multi-always.tar.gz
Merge branch 'multi2' into multi-alwaysmulti-always
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore14
-rw-r--r--src/CMakeLists.txt58
-rw-r--r--src/Makefile.Watcom212
-rw-r--r--src/Makefile.am121
-rw-r--r--src/Makefile.b32118
-rw-r--r--src/Makefile.inc99
-rw-r--r--src/Makefile.m32321
-rw-r--r--src/Makefile.netware498
-rw-r--r--src/Makefile.vc6522
-rw-r--r--src/curl.rc63
-rw-r--r--src/hugehelp.c.cvs6
-rw-r--r--src/hugehelp.h28
-rw-r--r--src/macos/MACINSTALL.TXT1
-rw-r--r--src/macos/curl.mcp.xml.sit.hqx1
-rw-r--r--src/macos/src/curl_GUSIConfig.cpp1
-rw-r--r--src/macos/src/macos_main.cpp1
-rw-r--r--src/makefile.amiga32
-rw-r--r--src/makefile.dj75
-rw-r--r--src/mkhelp.pl262
-rw-r--r--src/tool_binmode.c52
-rw-r--r--src/tool_binmode.h37
-rw-r--r--src/tool_bname.c50
-rw-r--r--src/tool_bname.h35
-rw-r--r--src/tool_cb_dbg.c275
-rw-r--r--src/tool_cb_dbg.h35
-rw-r--r--src/tool_cb_hdr.c225
-rw-r--r--src/tool_cb_hdr.h54
-rw-r--r--src/tool_cb_prg.c146
-rw-r--r--src/tool_cb_prg.h49
-rw-r--r--src/tool_cb_rea.c59
-rw-r--r--src/tool_cb_rea.h33
-rw-r--r--src/tool_cb_see.c135
-rw-r--r--src/tool_cb_see.h46
-rw-r--r--src/tool_cb_wrt.c152
-rw-r--r--src/tool_cb_wrt.h33
-rw-r--r--src/tool_cfgable.c128
-rw-r--r--src/tool_cfgable.h212
-rw-r--r--src/tool_convert.c150
-rw-r--r--src/tool_convert.h45
-rw-r--r--src/tool_dirhie.c149
-rw-r--r--src/tool_dirhie.h29
-rw-r--r--src/tool_doswin.c299
-rw-r--r--src/tool_doswin.h45
-rw-r--r--src/tool_easysrc.c227
-rw-r--r--src/tool_easysrc.h47
-rw-r--r--src/tool_formparse.c307
-rw-r--r--src/tool_formparse.h33
-rw-r--r--src/tool_getparam.c1697
-rw-r--r--src/tool_getparam.h49
-rw-r--r--src/tool_getpass.c260
-rw-r--r--src/tool_getpass.h36
-rw-r--r--src/tool_help.c245
-rw-r--r--src/tool_help.h29
-rw-r--r--src/tool_helpers.c78
-rw-r--r--src/tool_helpers.h31
-rw-r--r--src/tool_homedir.c112
-rw-r--r--src/tool_homedir.h28
-rw-r--r--src/tool_libinfo.c100
-rw-r--r--src/tool_libinfo.h34
-rw-r--r--src/tool_main.c110
-rw-r--r--src/tool_main.h44
-rw-r--r--src/tool_metalink.c906
-rw-r--r--src/tool_metalink.h161
-rw-r--r--src/tool_mfiles.c127
-rw-r--r--src/tool_mfiles.h46
-rw-r--r--src/tool_msgs.c100
-rw-r--r--src/tool_msgs.h31
-rw-r--r--src/tool_operate.c1783
-rw-r--r--src/tool_operate.h29
-rw-r--r--src/tool_operhlp.c257
-rw-r--r--src/tool_operhlp.h51
-rw-r--r--src/tool_panykey.c48
-rw-r--r--src/tool_panykey.h37
-rw-r--r--src/tool_paramhlp.c407
-rw-r--r--src/tool_paramhlp.h52
-rw-r--r--src/tool_parsecfg.c306
-rw-r--r--src/tool_parsecfg.h30
-rw-r--r--src/tool_sdecls.h153
-rw-r--r--src/tool_setopt.c528
-rw-r--r--src/tool_setopt.h144
-rw-r--r--src/tool_setup.h75
-rw-r--r--src/tool_sleep.c62
-rw-r--r--src/tool_sleep.h29
-rw-r--r--src/tool_urlglob.c614
-rw-r--r--src/tool_urlglob.h75
-rw-r--r--src/tool_util.c138
-rw-r--r--src/tool_util.h56
-rw-r--r--src/tool_version.h34
-rw-r--r--src/tool_vms.c219
-rw-r--r--src/tool_vms.h40
-rw-r--r--src/tool_writeenv.c116
-rw-r--r--src/tool_writeenv.h35
-rw-r--r--src/tool_writeout.c295
-rw-r--r--src/tool_writeout.h28
-rw-r--r--src/tool_xattr.c76
-rw-r--r--src/tool_xattr.h28
-rw-r--r--src/vc6curlsrc.dsp498
-rw-r--r--src/vc6curlsrc.dsw29
98 files changed, 16016 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 000000000..6835518d3
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,14 @@
+curl
+curl_config.h
+curl_config.h.in
+hugehelp.c
+stamp-h2
+Makefile.vc8.dist
+Makefile.vc9.dist
+version.h.dist
+tool_version.h.dist
+Makefile.vc10.dist
+config-win32.h
+*.a
+*.res
+*.nlm
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 000000000..eb6933e69
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,58 @@
+set(EXE_NAME curl)
+
+# First try to locate hugehelp.c to see if it has already been created
+# TODO Find the file WITHOUT adding a cache entry!!! Or else the user can delete the file after the script was first run, and the script won't notice it has gone.
+find_file(HUGEHELP_C_FILE hugehelp.c PATHS . NO_DEFAULT_PATH)
+if (NOT HUGEHELP_C_FILE)
+ message(STATUS "Warning: hugehelp.c file was not generated before. Generating an 'empty' file...")
+ file(WRITE hugehelp.c "/* built-in manual is disabled, blank function */\n#include \"hugehelp.h\"\nvoid hugehelp(void) {}\n\n")
+endif()
+
+transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
+include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
+
+if(MSVC)
+ list(APPEND CURL_SOURCE curl.rc)
+endif()
+
+add_executable(
+ ${EXE_NAME}
+ ${curl_SOURCES}
+ )
+
+source_group("cURLX source files" FILES ${CURLX_ONES})
+source_group("cURL source files" FILES ${CURL_CFILES})
+source_group("cURL header files" FILES ${CURL_HFILES})
+
+include_directories(
+ ${CURL_SOURCE_DIR}/lib # To be able to reach "setup_once.h"
+ ${CURL_BINARY_DIR}/lib # To be able to reach "curl_config.h"
+ ${CURL_BINARY_DIR}/include # To be able to reach "curl/curlbuild.h"
+ )
+
+
+# Setup dependencies
+setup_curl_dependencies(${EXE_NAME})
+target_link_libraries( ${EXE_NAME} libcurl )
+
+
+################################################################################
+
+#SET_TARGET_PROPERTIES(${EXE_NAME} ARCHIVE_OUTPUT_DIRECTORY "blah blah blah")
+#SET_TARGET_PROPERTIES(${EXE_NAME} RUNTIME_OUTPUT_DIRECTORY "blah blah blah")
+#SET_TARGET_PROPERTIES(${EXE_NAME} LIBRARY_OUTPUT_DIRECTORY "blah blah blah")
+
+# Add the postfix to the executable since it is not added automatically as for modules and shared libraries
+set_target_properties(${EXE_NAME} PROPERTIES
+ DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}")
+
+if(MSVC)
+ if(NOT BUILD_RELEASE_DEBUG_DIRS)
+ # Ugly workaround to remove the "/debug" or "/release" in each output
+ set_target_properties(${EXE_NAME} PROPERTIES PREFIX "../")
+ endif()
+endif()
+
+#INCLUDE(ModuleInstall OPTIONAL)
+
+install(TARGETS ${EXE_NAME} DESTINATION bin)
diff --git a/src/Makefile.Watcom b/src/Makefile.Watcom
new file mode 100644
index 000000000..6f7e8b261
--- /dev/null
+++ b/src/Makefile.Watcom
@@ -0,0 +1,212 @@
+#
+# Watcom / OpenWatcom / Win32 makefile for cURL.
+# G. Vanem <gvanem@broadpark.no>
+#
+
+!ifndef %watcom
+!error WATCOM environment variable not set!
+!endif
+
+!ifdef %libname
+LIBNAME = $(%libname)
+!else
+LIBNAME = libcurl
+!endif
+TARGETS = $(LIBNAME).dll $(LIBNAME)_imp.lib $(LIBNAME).lib
+
+CC = wcc386
+LD = wlink
+AR = wlib
+RC = wrc
+
+!ifdef __LOADDLL__
+! loaddll wcc386 wccd386
+! loaddll wpp386 wppd386
+! loaddll wlib wlibd
+! if $(__VERSION__) > 1270
+! loaddll wlink wlinkd
+! else
+! loaddll wlink wlink
+! endif
+!endif
+
+!ifdef __LINUX__
+DS = /
+CP = cp
+MD = mkdir -p
+RD = rmdir -p
+RM = rm -f
+!else
+DS = $(X)\$(X)
+CP = copy 2>NUL
+MD = mkdir
+RD = rmdir /q /s 2>NUL
+!if $(__VERSION__) < 1250
+RM = del /q /f 2>NUL
+!else
+RM = rm -f
+!endif
+!endif
+
+SYS_INCL = -I$(%watcom)$(DS)h$(DS)nt -I$(%watcom)$(DS)h
+SYS_LIBS = $(%watcom)$(DS)lib386$(DS)nt;$(%watcom)$(DS)lib386
+
+CFLAGS = -3r -mf -hc -zff -zgf -zq -zm -s -fr=con -w2 -fpi -oilrtfm &
+ -wcd=201 -bt=nt -bc -d+ -dWIN32 -dHAVE_STRTOLL &
+ -I..$(DS)include -I..$(DS)lib $(SYS_INCL)
+
+!ifdef %debug
+DEBUG = -dDEBUG=1 -dDEBUGBUILD
+CFLAGS += -d3 $(DEBUG)
+!else
+CFLAGS += -d0
+!endif
+
+!ifdef %use_ipv6
+CFLAGS += -d_WIN32_WINNT=0x0501 -dENABLE_IPV6
+!endif
+
+#
+# Change to suite.
+#
+!ifdef %zlib_root
+ZLIB_ROOT = $(%zlib_root)
+!else
+ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.7
+!endif
+
+!ifdef %libssh2_root
+LIBSSH2_ROOT = $(%libssh2_root)
+!else
+LIBSSH2_ROOT = ..$(DS)..$(DS)libssh2-1.4.2
+!endif
+
+!ifdef %librtmp_root
+LIBRTMP_ROOT = $(%librtmp_root)
+!else
+LIBRTMP_ROOT = ..$(DS)..$(DS)rtmpdump-2.3
+!endif
+
+!ifdef %openssl_root
+OPENSSL_ROOT = $(%openssl_root)
+!else
+OPENSSL_ROOT = ..$(DS)..$(DS)openssl-0.9.8x
+!endif
+
+!ifdef %ares_root
+ARES_ROOT = $(%ares_root)
+!else
+ARES_ROOT = ..$(DS)ares
+!endif
+
+!ifdef %use_ssl
+CFLAGS += -wcd=138 -dUSE_OPENSSL -dUSE_SSLEAY -I$(OPENSSL_ROOT)$(DS)inc32
+!endif
+
+OBJ_DIR = WC_Win32.obj
+LINK_ARG = $(OBJ_DIR)$(DS)wlink.arg
+
+# In order to process Makefile.inc wmake must be called with -u switch!
+!ifndef %MAKEFLAGS
+!error You MUST call wmake with the -u switch!
+!else
+!include Makefile.inc
+!endif
+# For now we still define the CURLX_ONES sources here unless we know how
+# to split off the prefixed path.
+CURLX_SOURCES = rawstr.c nonblock.c
+
+OBJS = $(CURL_CFILES:.c=.obj)
+!ifdef %curl_static
+CFLAGS += -DCURL_STATICLIB
+!else
+CFLAGS += -br
+OBJS += $(CURLX_SOURCES:.c=.obj)
+!endif
+!ifdef __LINUX__
+OBJS = $OBJ_DIR/$(OBJS: = $OBJ_DIR/)
+
+!else
+OBJS = $OBJ_DIR\$(OBJS: = $OBJ_DIR\)
+!endif
+
+RESOURCE = $(OBJ_DIR)$(DS)curl.res
+
+all: hugehelp.c $(OBJ_DIR) curl.exe .SYMBOLIC
+ @echo Welcome to cURL
+
+clean: .SYMBOLIC
+ -$(RM) $(OBJS)
+ -$(RM) $(RESOURCE) $(LINK_ARG)
+
+vclean distclean: clean .SYMBOLIC
+ -$(RD) $(OBJ_DIR)
+ -$(RM) curl.exe curl.map curl.sym hugehelp.c
+
+hugehelp.c: hugehelp.c.cvs
+ $(CP) $[@ $^@
+
+hugehelp.c.cvs: .EXISTSONLY
+ $(CP) hugehelp.c $^@
+
+$(OBJ_DIR):
+ -$(MD) $^@
+
+curl.exe: $(OBJS) $(RESOURCE) $(LINK_ARG)
+ $(LD) name $^@ @$]@
+
+$(RESOURCE): curl.rc
+ $(RC) $(DEBUG) -q -r -zm -bt=nt -I..$(DS)include $(SYS_INCL) $[@ -fo=$^@
+
+# suffix search path - vpath-like hack
+.c: ..$(DS)lib
+
+.ERASE
+.c{$(OBJ_DIR)}.obj:
+ $(CC) $(CFLAGS) $[@ -fo=$^@
+
+$(LINK_ARG): $(__MAKEFILES__)
+ %create $^@
+ @%append $^@ system nt
+ @%append $^@ file { $(OBJS) }
+!ifdef %debug
+ @%append $^@ debug all
+ @%append $^@ option symfile
+!endif
+ @%append $^@ option quiet, map, caseexact, eliminate,
+ @%append $^@ res=$(RESOURCE) libpath $(SYS_LIBS)
+!ifdef %curl_static
+ @%append $^@ library wldap32.lib
+ @%append $^@ library ..$(DS)lib$(DS)$(LIBNAME).lib
+!ifdef %use_zlib
+ @%append $^@ library $(ZLIB_ROOT)$(DS)zlib.lib
+!endif
+!ifdef %use_rtmp
+ @%append $^@ library $(LIBRTMP_ROOT)$(DS)librtmp$(DS)librtmp.lib, winmm.lib
+!endif
+!ifdef %use_ssh2
+ @%append $^@ library $(LIBSSH2_ROOT)$(DS)win32$(DS)libssh2.lib
+!endif
+!ifdef %use_ssl
+ @%append $^@ library $(OPENSSL_ROOT)$(DS)out32$(DS)libeay32.lib, $(OPENSSL_ROOT)$(DS)out32$(DS)ssleay32.lib
+!endif
+!ifdef %use_ares
+ @%append $^@ library $(ARES_ROOT)$(DS)cares.lib
+!endif
+!ifdef %use_winidn
+! if $(__VERSION__) > 1290
+ @%append $^@ library normaliz.lib
+! else
+ @%append $^@ import '_IdnToAscii@20' 'NORMALIZ.DLL'.'IdnToAscii'
+ @%append $^@ import '_IdnToUnicode@20' 'NORMALIZ.DLL'.'IdnToUnicode'
+! endif
+!endif
+!else
+ @%append $^@ library ..$(DS)lib$(DS)$(LIBNAME)_imp.lib
+!endif
+!ifeq USE_WATT32 1
+ @%append $^@ library $(%watt_root)$(DS)lib$(DS)wattcpw_imp.lib
+!else
+ @%append $^@ library ws2_32.lib
+!endif
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 000000000..6de750114
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,121 @@
+#***************************************************************************
+# _ _ ____ _
+# Project ___| | | | _ \| |
+# / __| | | | |_) | |
+# | (__| |_| | _ <| |___
+# \___|\___/|_| \_\_____|
+#
+# Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://curl.haxx.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+###########################################################################
+AUTOMAKE_OPTIONS = foreign nostdinc
+
+# Specify our include paths here, and do it relative to $(top_srcdir) and
+# $(top_builddir), to ensure that these paths which belong to the library
+# being currently built and tested are searched before the library which
+# might possibly already be installed in the system.
+#
+# $(top_builddir)/include/curl for generated curlbuild.h included from curl.h
+# $(top_builddir)/include for generated curlbuild.h included from lib/setup.h
+# $(top_srcdir)/include is for libcurl's external include files
+# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
+# $(top_builddir)/src is for curl's generated src/curl_config.h file
+# $(top_srcdir)/lib is for libcurl's lib/setup.h and other "borrowed" files
+# $(top_srcdir)/src is for curl's src/tool_setup.h and "curl-private" files
+
+AM_CPPFLAGS = -I$(top_builddir)/include/curl \
+ -I$(top_builddir)/include \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/lib \
+ -I$(top_builddir)/src \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/src
+
+bin_PROGRAMS = curl
+
+# Mostly for Windows build targets, when using static libcurl
+if USE_CPPFLAG_CURL_STATICLIB
+AM_CPPFLAGS += -DCURL_STATICLIB
+endif
+
+include Makefile.inc
+
+# This might hold -Werror
+CFLAGS += @CURL_CFLAG_EXTRAS@ @LIBMETALINK_CFLAGS@
+
+# Prevent LIBS from being used for all link targets
+LIBS = $(BLANK_AT_MAKETIME)
+
+if USE_EXPLICIT_LIB_DEPS
+curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBMETALINK_LIBS@ @LIBCURL_LIBS@
+else
+curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBMETALINK_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@
+endif
+
+curl_LDFLAGS = @LIBMETALINK_LDFLAGS@
+curl_DEPENDENCIES = $(top_builddir)/lib/libcurl.la
+BUILT_SOURCES = hugehelp.c
+CLEANFILES = hugehelp.c
+# Use the C locale to ensure that only ASCII characters appear in the
+# embedded text.
+NROFF=env LC_ALL=C @NROFF@ @MANOPT@ # figured out by the configure script
+
+EXTRA_DIST = mkhelp.pl makefile.dj Makefile.vc6 Makefile.b32 Makefile.m32 \
+ macos/curl.mcp.xml.sit.hqx \
+ macos/MACINSTALL.TXT macos/src/curl_GUSIConfig.cpp vc6curlsrc.dsp \
+ macos/src/macos_main.cpp makefile.amiga curl.rc \
+ Makefile.netware Makefile.inc Makefile.Watcom vc6curlsrc.dsw \
+ CMakeLists.txt
+
+MANPAGE=$(top_srcdir)/docs/curl.1
+README=$(top_srcdir)/docs/MANUAL
+MKHELP=$(top_srcdir)/src/mkhelp.pl
+HUGE=hugehelp.c
+
+if USE_MANUAL
+# Here are the stuff to create a built-in manual
+
+if HAVE_LIBZ
+# This generates the hugehelp.c file in both uncompressed and compressed formats
+$(HUGE): $(README) $(MANPAGE) mkhelp.pl
+ echo '#include "tool_setup.h"' > $(HUGE)
+ echo '#ifndef HAVE_LIBZ' >> $(HUGE)
+ $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) $(README) >> $(HUGE)
+ echo '#else' >> $(HUGE)
+ $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) -c $(README) >> $(HUGE)
+ echo '#endif /* HAVE_LIBZ */' >> $(HUGE)
+else # HAVE_LIBZ
+# This generates the hugehelp.c file uncompressed only
+$(HUGE): $(README) $(MANPAGE) mkhelp.pl
+ echo '#include "tool_setup.h"' > $(HUGE)
+ $(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) $(README) >> $(HUGE)
+endif
+
+else # USE_MANUAL
+# built-in manual has been disabled, make a blank file
+$(HUGE):
+ echo "/* built-in manual is disabled, blank function */" > $(HUGE)
+ echo '#include "hugehelp.h"' >> $(HUGE)
+ echo "void hugehelp(void) {}" >>$(HUGE)
+endif
+
+# ignore hugehelp.c since it is generated source code and it plays by slightly
+# different rules!
+checksrc:
+ @@PERL@ $(top_srcdir)/lib/checksrc.pl -D$(top_srcdir)/src -Whugehelp.c $(curl_SOURCES)
+
+if CURLDEBUG
+# for debug builds, we scan the sources on all regular make invokes
+all-local: checksrc
+endif
diff --git a/src/Makefile.b32 b/src/Makefile.b32
new file mode 100644
index 000000000..29d30dfeb
--- /dev/null
+++ b/src/Makefile.b32
@@ -0,0 +1,118 @@
+############################################################
+#
+# Makefile.b32 - Borland's C++ Compiler 5.X
+#
+# 'src' directory
+#
+# 'BCCDIR' has to be set up to point to the base directory
+# of the compiler, i.e. SET BCCDIR = c:\Borland\BCC55
+#
+# Initially written by Jaepil Kim, pit@paradise.net.nz
+############################################################
+
+!if "$(__MAKE__)" == ""
+!error __MAKE__ not defined. Use Borlands's MAKE to process this makefile.
+!endif
+
+# Borland's $(MAKEDIR) expands to the path where make.exe is located,
+# use this feature to define BCCDIR when user has not defined BCCDIR.
+!ifndef BCCDIR
+BCCDIR = $(MAKEDIR)\..
+!endif
+
+# Edit the path below to point to the base of your Zlib sources.
+!ifndef ZLIB_PATH
+ZLIB_PATH = ..\..\zlib-1.2.7
+!endif
+
+# Edit the path below to point to the base of your OpenSSL package.
+!ifndef OPENSSL_PATH
+OPENSSL_PATH = ..\..\openssl-0.9.8x
+!endif
+
+# Set program's name
+PROGNAME = curl.exe
+
+# Setup environment
+CC_CMD = bcc32 -q -c
+LD = bcc32
+RM = del 2>NUL
+MKDIR = md
+RMDIR = rd /q 2>nul
+COPY = $(COMSPEC) /c copy /y
+
+CC_FLAGS = -5 -O2 -tWM -w -w-aus -w-ccc -w-dup -w-prc -w-pro -w-rch -w-sig -w-spa -w-inl -w-pia -w-pin -Dinline=__inline
+LDFLAGS = -q -lq -lap
+
+SRCDIRS = .;..\lib
+OBJDIR = .\BCC_objs
+INCDIRS = -I.;..\include;..\lib
+LINKLIB = $(BCCDIR)\lib\cw32mt.lib
+DEFINES = -DNDEBUG -DWIN32
+
+!ifdef DYNAMIC
+LIBCURL_LIB = ..\lib\libcurl_imp.lib
+!else
+LIBCURL_LIB = ..\lib\libcurl.lib
+DEFINES = $(DEFINES) -DCURL_STATICLIB
+!endif
+
+# ZLIB support is enabled setting WITH_ZLIB=1
+!ifdef WITH_ZLIB
+DEFINES = $(DEFINES) -DHAVE_LIBZ -DHAVE_ZLIB_H
+INCDIRS = $(INCDIRS);$(ZLIB_PATH)
+LINKLIB = $(LINKLIB) $(ZLIB_PATH)\zlib.lib
+!endif
+
+# SSL support is enabled setting WITH_SSL=1
+!ifdef WITH_SSL
+DEFINES = $(DEFINES) -DUSE_SSLEAY
+INCDIRS = $(INCDIRS);$(OPENSSL_PATH)\inc32;$(OPENSSL_PATH)\inc32\openssl
+LINKLIB = $(LINKLIB) $(OPENSSL_PATH)\out32\ssleay32.lib $(OPENSSL_PATH)\out32\libeay32.lib
+!endif
+
+.autodepend
+
+.path.c = $(SRCDIRS)
+.path.obj = $(OBJDIR)
+
+# Makefile.inc provides the CSOURCES and HHEADERS defines
+!undef top_srcdir
+!include Makefile.inc
+
+CSOURCES = $(CURL_CFILES) $(CURLX_ONES:/lib/=)
+OBJECTS = $(CSOURCES:.c=.obj)
+
+.c.obj:
+ $(CC_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$@ $<
+
+all: $(OBJDIR) hugehelp $(PROGNAME)
+
+clean:
+ cd $(OBJDIR)
+ @-$(RM) $(OBJECTS)
+ cd ..
+ @-$(RMDIR) $(OBJDIR)
+ @-$(RM) $(PROGNAME)
+ @-$(RM) curl.tds
+
+$(OBJDIR):
+ @-$(RMDIR) $(OBJDIR)
+ @-$(MKDIR) $(OBJDIR)
+
+!ifdef WITH_ZLIB
+hugehelp: ..\docs\MANUAL ..\docs\curl.1 mkhelp.pl
+ groff -Tascii -man -P -c ../docs/curl.1 > hugehelp.tmp
+ perl -w mkhelp.pl -c ../docs/MANUAL < hugehelp.tmp > hugehelp.c
+ @-$(RM) hugehelp.tmp
+!else
+hugehelp:
+ $(COPY) hugehelp.c.cvs hugehelp.c
+!endif
+
+$(PROGNAME): $(OBJECTS) $(LIBCURL_LIB) $(LINKLIB)
+ @-$(RM) $(PROGNAME)
+ $(LD) $(LDFLAGS) -e$@ $**
+
+
+# End of Makefile.b32
diff --git a/src/Makefile.inc b/src/Makefile.inc
new file mode 100644
index 000000000..76d6b7b7a
--- /dev/null
+++ b/src/Makefile.inc
@@ -0,0 +1,99 @@
+# ./src/Makefile.inc
+# Using the backslash as line continuation character might be problematic
+# with some make flavours, as Watcom's wmake showed us already. If we
+# ever want to change this in a portable manner then we should consider
+# this idea (posted to the libcurl list by Adam Kellas):
+# CSRC1 = file1.c file2.c file3.c
+# CSRC2 = file4.c file5.c file6.c
+# CSOURCES = $(CSRC1) $(CSRC2)
+
+# libcurl has sources that provide functions named curlx_* that aren't part of
+# the official API, but we re-use the code here to avoid duplication.
+CURLX_ONES = $(top_srcdir)/lib/strtoofft.c \
+ $(top_srcdir)/lib/strdup.c \
+ $(top_srcdir)/lib/rawstr.c \
+ $(top_srcdir)/lib/nonblock.c
+
+CURL_CFILES = hugehelp.c \
+ tool_binmode.c \
+ tool_bname.c \
+ tool_cb_dbg.c \
+ tool_cb_hdr.c \
+ tool_cb_prg.c \
+ tool_cb_rea.c \
+ tool_cb_see.c \
+ tool_cb_wrt.c \
+ tool_cfgable.c \
+ tool_convert.c \
+ tool_dirhie.c \
+ tool_doswin.c \
+ tool_easysrc.c \
+ tool_formparse.c \
+ tool_getparam.c \
+ tool_getpass.c \
+ tool_help.c \
+ tool_helpers.c \
+ tool_homedir.c \
+ tool_libinfo.c \
+ tool_main.c \
+ tool_metalink.c \
+ tool_mfiles.c \
+ tool_msgs.c \
+ tool_operate.c \
+ tool_operhlp.c \
+ tool_panykey.c \
+ tool_paramhlp.c \
+ tool_parsecfg.c \
+ tool_setopt.c \
+ tool_sleep.c \
+ tool_urlglob.c \
+ tool_util.c \
+ tool_vms.c \
+ tool_writeenv.c \
+ tool_writeout.c \
+ tool_xattr.c
+
+CURL_HFILES = hugehelp.h \
+ tool_binmode.h \
+ tool_bname.h \
+ tool_cb_dbg.h \
+ tool_cb_hdr.h \
+ tool_cb_prg.h \
+ tool_cb_rea.h \
+ tool_cb_see.h \
+ tool_cb_wrt.h \
+ tool_cfgable.h \
+ tool_convert.h \
+ tool_dirhie.h \
+ tool_doswin.h \
+ tool_easysrc.h \
+ tool_formparse.h \
+ tool_getparam.h \
+ tool_getpass.h \
+ tool_help.h \
+ tool_helpers.h \
+ tool_homedir.h \
+ tool_libinfo.h \
+ tool_main.h \
+ tool_metalink.h \
+ tool_mfiles.h \
+ tool_msgs.h \
+ tool_operate.h \
+ tool_operhlp.h \
+ tool_panykey.h \
+ tool_paramhlp.h \
+ tool_parsecfg.h \
+ tool_sdecls.h \
+ tool_setopt.h \
+ tool_setup.h \
+ tool_sleep.h \
+ tool_urlglob.h \
+ tool_util.h \
+ tool_version.h \
+ tool_vms.h \
+ tool_writeenv.h \
+ tool_writeout.h \
+ tool_xattr.h
+
+curl_SOURCES = $(CURL_CFILES) $(CURLX_ONES) $(CURL_HFILES)
+
diff --git a/src/Makefile.m32 b/src/Makefile.m32
new file mode 100644
index 000000000..766fc733f
--- /dev/null
+++ b/src/Makefile.m32
@@ -0,0 +1,321 @@
+###########################################################################
+#
+## Makefile for building curl.exe with MingW (GCC-3.2 or later)
+## and optionally OpenSSL (0.9.8), libssh2 (1.3), zlib (1.2.5), librtmp (2.3)
+##
+## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...]
+## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-spi-winidn
+##
+## Hint: you can also set environment vars to control the build, f.e.:
+## set ZLIB_PATH=c:/zlib-1.2.7
+## set ZLIB=1
+#
+###########################################################################
+
+# Edit the path below to point to the base of your Zlib sources.
+ifndef ZLIB_PATH
+ZLIB_PATH = ../../zlib-1.2.7
+endif
+# Edit the path below to point to the base of your OpenSSL package.
+ifndef OPENSSL_PATH
+OPENSSL_PATH = ../../openssl-0.9.8x
+endif
+# Edit the path below to point to the base of your LibSSH2 package.
+ifndef LIBSSH2_PATH
+LIBSSH2_PATH = ../../libssh2-1.4.2
+endif
+# Edit the path below to point to the base of your librtmp package.
+ifndef LIBRTMP_PATH
+LIBRTMP_PATH = ../../librtmp-2.3
+endif
+# Edit the path below to point to the base of your libmetalink package.
+ifndef LIBMETALINK_PATH
+LIBMETALINK_PATH = ../../libmetalink-0.1.2
+endif
+# Edit the path below to point to the base of your libexpat package.
+ifndef LIBEXPAT_PATH
+LIBEXPAT_PATH = ../../expat-2.1.0
+endif
+# Edit the path below to point to the base of your libxml2 package.
+ifndef LIBXML2_PATH
+LIBXML2_PATH = ../../libxml2-2.9.0
+endif
+# Edit the path below to point to the base of your libidn package.
+ifndef LIBIDN_PATH
+LIBIDN_PATH = ../../libidn-1.18
+endif
+# Edit the path below to point to the base of your MS IDN package.
+# Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1
+# http://www.microsoft.com/downloads/en/details.aspx?FamilyID=ad6158d7-ddba-416a-9109-07607425a815
+ifndef WINIDN_PATH
+WINIDN_PATH = ../../Microsoft IDN Mitigation APIs
+endif
+# Edit the path below to point to the base of your Novell LDAP NDK.
+ifndef LDAP_SDK
+LDAP_SDK = c:/novell/ndk/cldapsdk/win32
+endif
+
+PROOT = ..
+
+# Edit the path below to point to the base of your c-ares package.
+ifndef LIBCARES_PATH
+LIBCARES_PATH = $(PROOT)/ares
+endif
+
+# Edit the var below to set to your architecture or set environment var.
+ifndef ARCH
+ARCH = w32
+endif
+
+CC = $(CROSSPREFIX)gcc
+CFLAGS = -g -O2 -Wall
+CFLAGS += -fno-strict-aliasing
+ifeq ($(ARCH),w64)
+CFLAGS += -D_AMD64_
+endif
+# comment LDFLAGS below to keep debug info
+LDFLAGS = -s
+AR = $(CROSSPREFIX)ar
+RC = $(CROSSPREFIX)windres
+RCFLAGS = --include-dir=$(PROOT)/include -O COFF -i
+
+# We may need these someday
+# PERL = perl
+# NROFF = nroff
+
+# Platform-dependent helper tool macros
+ifeq ($(findstring /sh,$(SHELL)),/sh)
+DEL = rm -f $1
+RMDIR = rm -fr $1
+MKDIR = mkdir -p $1
+COPY = -cp -afv $1 $2
+#COPYR = -cp -afr $1/* $2
+COPYR = -rsync -aC $1/* $2
+TOUCH = touch $1
+CAT = cat
+ECHONL = echo ""
+DL = '
+else
+ifeq "$(OS)" "Windows_NT"
+DEL = -del 2>NUL /q /f $(subst /,\,$1)
+RMDIR = -rd 2>NUL /q /s $(subst /,\,$1)
+else
+DEL = -del 2>NUL $(subst /,\,$1)
+RMDIR = -deltree 2>NUL /y $(subst /,\,$1)
+endif
+MKDIR = -md 2>NUL $(subst /,\,$1)
+COPY = -copy 2>NUL /y $(subst /,\,$1) $(subst /,\,$2)
+COPYR = -xcopy 2>NUL /q /y /e $(subst /,\,$1) $(subst /,\,$2)
+TOUCH = copy 2>&1>NUL /b $(subst /,\,$1) +,,
+CAT = type
+ECHONL = $(ComSpec) /c echo.
+endif
+
+########################################################
+## Nothing more to do below this line!
+
+ifeq ($(findstring -dyn,$(CFG)),-dyn)
+DYN = 1
+endif
+ifeq ($(findstring -ares,$(CFG)),-ares)
+ARES = 1
+endif
+ifeq ($(findstring -rtmp,$(CFG)),-rtmp)
+RTMP = 1
+SSL = 1
+ZLIB = 1
+endif
+ifeq ($(findstring -ssh2,$(CFG)),-ssh2)
+SSH2 = 1
+SSL = 1
+ZLIB = 1
+endif
+ifeq ($(findstring -ssl,$(CFG)),-ssl)
+SSL = 1
+endif
+ifeq ($(findstring -zlib,$(CFG)),-zlib)
+ZLIB = 1
+endif
+ifeq ($(findstring -idn,$(CFG)),-idn)
+IDN = 1
+endif
+ifeq ($(findstring -winidn,$(CFG)),-winidn)
+WINIDN = 1
+endif
+ifeq ($(findstring -sspi,$(CFG)),-sspi)
+SSPI = 1
+endif
+ifeq ($(findstring -spnego,$(CFG)),-spnego)
+SPNEGO = 1
+endif
+ifeq ($(findstring -ldaps,$(CFG)),-ldaps)
+LDAPS = 1
+endif
+ifeq ($(findstring -ipv6,$(CFG)),-ipv6)
+IPV6 = 1
+endif
+ifeq ($(findstring -metalink,$(CFG)),-metalink)
+METALINK = 1
+endif
+ifeq ($(findstring -winssl,$(CFG)),-winssl)
+WINSSL = 1
+SSPI = 1
+endif
+
+INCLUDES = -I. -I../include -I../lib
+
+ifdef DYN
+ curl_DEPENDENCIES = $(PROOT)/lib/libcurldll.a $(PROOT)/lib/libcurl.dll
+ curl_LDADD = -L$(PROOT)/lib -lcurldll
+else
+ curl_DEPENDENCIES = $(PROOT)/lib/libcurl.a
+ curl_LDADD = -L$(PROOT)/lib -lcurl
+ CFLAGS += -DCURL_STATICLIB
+ LDFLAGS += -static
+endif
+ifdef ARES
+ ifndef DYN
+ curl_DEPENDENCIES += $(LIBCARES_PATH)/libcares.a
+ endif
+ CFLAGS += -DUSE_ARES
+ curl_LDADD += -L"$(LIBCARES_PATH)" -lcares
+endif
+ifdef RTMP
+ CFLAGS += -DUSE_LIBRTMP
+ curl_LDADD += -L"$(LIBRTMP_PATH)/librtmp" -lrtmp -lwinmm
+endif
+ifdef SSH2
+ CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H
+ curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2
+endif
+ifdef SSL
+ ifndef OPENSSL_INCLUDE
+ ifeq "$(wildcard $(OPENSSL_PATH)/outinc)" "$(OPENSSL_PATH)/outinc"
+ OPENSSL_INCLUDE = $(OPENSSL_PATH)/outinc
+ endif
+ ifeq "$(wildcard $(OPENSSL_PATH)/include)" "$(OPENSSL_PATH)/include"
+ OPENSSL_INCLUDE = $(OPENSSL_PATH)/include
+ endif
+ endif
+ ifneq "$(wildcard $(OPENSSL_INCLUDE)/openssl/opensslv.h)" "$(OPENSSL_INCLUDE)/openssl/opensslv.h"
+ $(error Invalid path to OpenSSL package: $(OPENSSL_PATH))
+ endif
+ ifndef OPENSSL_LIBPATH
+ OPENSSL_LIBS = -lssl -lcrypto
+ ifeq "$(wildcard $(OPENSSL_PATH)/out)" "$(OPENSSL_PATH)/out"
+ OPENSSL_LIBPATH = $(OPENSSL_PATH)/out
+ ifdef DYN
+ OPENSSL_LIBS = -lssl32 -leay32
+ endif
+ endif
+ ifeq "$(wildcard $(OPENSSL_PATH)/lib)" "$(OPENSSL_PATH)/lib"
+ OPENSSL_LIBPATH = $(OPENSSL_PATH)/lib
+ endif
+ endif
+ ifndef DYN
+ OPENSSL_LIBS += -lgdi32 -lcrypt32
+ endif
+ INCLUDES += -I"$(OPENSSL_INCLUDE)"
+ CFLAGS += -DUSE_SSLEAY -DUSE_OPENSSL
+ curl_LDADD += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS)
+endif
+ifdef ZLIB
+ INCLUDES += -I"$(ZLIB_PATH)"
+ CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H
+ curl_LDADD += -L"$(ZLIB_PATH)" -lz
+endif
+ifdef IDN
+ CFLAGS += -DUSE_LIBIDN
+ curl_LDADD += -L"$(LIBIDN_PATH)/lib" -lidn
+else
+ifdef WINIDN
+ CFLAGS += -DUSE_WIN32_IDN
+ curl_LDADD += -L"$(WINIDN_PATH)" -lnormaliz
+endif
+endif
+ifdef METALINK
+ INCLUDES += -I"$(LIBMETALINK_PATH)/include"
+ CFLAGS += -DUSE_METALINK
+ curl_LDADD += -L"$(LIBMETALINK_PATH)/lib" -lmetalink
+ ifndef DYN
+ ifeq ($(findstring libexpat_metalink_parser.o,$(shell $(AR) t "$(LIBMETALINK_PATH)/lib/libmetalink.a")),libexpat_metalink_parser.o)
+ curl_LDADD += -L"$(LIBEXPAT_PATH)/lib" -lexpat
+ else
+ curl_LDADD += -L"$(LIBXML2_PATH)/lib" -lxml2
+ endif
+ endif
+endif
+ifdef SSPI
+ CFLAGS += -DUSE_WINDOWS_SSPI
+ ifdef WINSSL
+ CFLAGS += -DUSE_SCHANNEL
+ endif
+endif
+ifdef SPNEGO
+ CFLAGS += -DHAVE_SPNEGO
+endif
+ifdef IPV6
+ CFLAGS += -DENABLE_IPV6 -D_WIN32_WINNT=0x0501
+endif
+ifdef LDAPS
+ CFLAGS += -DHAVE_LDAP_SSL
+endif
+ifdef USE_LDAP_NOVELL
+ CFLAGS += -DCURL_HAS_NOVELL_LDAPSDK
+ curl_LDADD += -L"$(LDAP_SDK)/lib/mscvc" -lldapsdk -lldapssl -lldapx
+endif
+ifdef USE_LDAP_OPENLDAP
+ CFLAGS += -DCURL_HAS_OPENLDAP_LDAPSDK
+ curl_LDADD += -L"$(LDAP_SDK)/lib" -lldap -llber
+endif
+ifndef USE_LDAP_NOVELL
+ifndef USE_LDAP_OPENLDAP
+curl_LDADD += -lwldap32
+endif
+endif
+curl_LDADD += -lws2_32
+
+# Makefile.inc provides the CSOURCES and HHEADERS defines
+include Makefile.inc
+
+curl_PROGRAMS = curl.exe
+curl_OBJECTS := $(patsubst %.c,%.o,$(strip $(CURL_CFILES)))
+curlx_OBJECTS := $(patsubst %.c,%.o,$(notdir $(strip $(CURLX_ONES))))
+ifdef DYN
+curl_OBJECTS += $(curlx_OBJECTS)
+vpath %.c $(PROOT)/lib
+endif
+
+RESOURCE = curl.res
+
+
+all: $(curl_PROGRAMS)
+
+curl.exe: $(RESOURCE) $(curl_OBJECTS) $(curl_DEPENDENCIES)
+ $(call DEL, $@)
+ $(CC) $(LDFLAGS) -o $@ $< $(curl_OBJECTS) $(curl_LDADD)
+
+# We don't have nroff normally under win32
+# hugehelp.c: $(PROOT)/docs/MANUAL $(PROOT)/docs/curl.1 mkhelp.pl
+# @$(call DEL, hugehelp.c)
+# $(NROFF) -man $(PROOT)/docs/curl.1 | $(PERL) mkhelp.pl $(PROOT)/docs/MANUAL > hugehelp.c
+
+hugehelp.c:
+ @echo Creating $@
+ @$(call COPY, $@.cvs, $@)
+
+%.o: %.c
+ $(CC) $(INCLUDES) $(CFLAGS) -c $<
+
+%.res: %.rc
+ $(RC) $(RCFLAGS) $< -o $@
+
+clean:
+ifeq "$(wildcard hugehelp.c.cvs)" "hugehelp.c.cvs"
+ @$(call DEL, hugehelp.c)
+endif
+ @$(call DEL, $(curl_OBJECTS) $(curlx_OBJECTS) $(RESOURCE))
+
+distclean vclean: clean
+ @$(call DEL, $(curl_PROGRAMS))
+
diff --git a/src/Makefile.netware b/src/Makefile.netware
new file mode 100644
index 000000000..93bbe8b0c
--- /dev/null
+++ b/src/Makefile.netware
@@ -0,0 +1,498 @@
+#################################################################
+#
+## Makefile for building curl.nlm (NetWare version - gnu make)
+## Use: make -f Makefile.netware
+##
+## Comments to: Guenter Knauf http://www.gknw.net/phpbb
+#
+#################################################################
+
+# Edit the path below to point to the base of your Novell NDK.
+ifndef NDKBASE
+NDKBASE = c:/novell
+endif
+
+# Edit the path below to point to the base of your Zlib sources.
+ifndef ZLIB_PATH
+ZLIB_PATH = ../../zlib-1.2.7
+endif
+
+# Edit the path below to point to the base of your OpenSSL package.
+ifndef OPENSSL_PATH
+OPENSSL_PATH = ../../openssl-0.9.8x
+endif
+
+# Edit the path below to point to the base of your LibSSH2 package.
+ifndef LIBSSH2_PATH
+LIBSSH2_PATH = ../../libssh2-1.4.2
+endif
+
+# Edit the path below to point to the base of your axTLS package.
+ifndef AXTLS_PATH
+AXTLS_PATH = ../../axTLS-1.2.7
+endif
+
+# Edit the path below to point to the base of your libidn package.
+ifndef LIBIDN_PATH
+LIBIDN_PATH = ../../libidn-1.18
+endif
+
+# Edit the path below to point to the base of your librtmp package.
+ifndef LIBRTMP_PATH
+LIBRTMP_PATH = ../../librtmp-2.3
+endif
+
+# Edit the path below to point to the base of your fbopenssl package.
+ifndef FBOPENSSL_PATH
+FBOPENSSL_PATH = ../../fbopenssl-0.4
+endif
+
+# Edit the path below to point to the base of your libmetalink package.
+ifndef LIBMETALINK_PATH
+LIBMETALINK_PATH = ../../libmetalink-0.1.0
+endif
+
+# Edit the path below to point to the base of your libexpat package.
+ifndef LIBEXPAT_PATH
+LIBEXPAT_PATH = ../../expat-2.1.0
+endif
+
+# Edit the path below to point to the base of your libXML2 package.
+ifndef LIBXML2_PATH
+LIBXML2_PATH = ../../libxml2-2.8.0
+endif
+
+# Edit the path below to point to the base of your c-ares package.
+ifndef LIBCARES_PATH
+LIBCARES_PATH = ../ares
+endif
+
+ifndef INSTDIR
+INSTDIR = ..$(DS)curl-$(LIBCURL_VERSION_STR)-bin-nw
+endif
+
+# Edit the vars below to change NLM target settings.
+TARGET = curl
+VERSION = $(LIBCURL_VERSION)
+COPYR = Copyright (C) $(LIBCURL_COPYRIGHT_STR)
+DESCR = cURL $(LIBCURL_VERSION_STR) ($(LIBARCH)) - http://curl.haxx.se
+MTSAFE = YES
+STACK = 64000
+SCREEN = $(TARGET) commandline utility
+# Comment the line below if you dont want to load protected automatically.
+# LDRING = 3
+
+# Uncomment the next line to enable linking with POSIX semantics.
+# POSIXFL = 1
+
+# Edit the var below to point to your lib architecture.
+ifndef LIBARCH
+LIBARCH = LIBC
+endif
+
+# must be equal to NDEBUG or DEBUG, CURLDEBUG
+ifndef DB
+DB = NDEBUG
+endif
+# Optimization: -O<n> or debugging: -g
+ifeq ($(DB),NDEBUG)
+ OPT = -O2
+ OBJDIR = release
+else
+ OPT = -g
+ OBJDIR = debug
+endif
+
+# The following lines defines your compiler.
+ifdef CWFolder
+ METROWERKS = $(CWFolder)
+endif
+ifdef METROWERKS
+ # MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support
+ MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support/Metrowerks Support
+ CC = mwccnlm
+else
+ CC = gcc
+endif
+PERL = perl
+# Here you can find a native Win32 binary of the original awk:
+# http://www.gknw.net/development/prgtools/awk-20100523.zip
+AWK = awk
+CP = cp -afv
+MKDIR = mkdir
+# RM = rm -f
+# If you want to mark the target as MTSAFE you will need a tool for
+# generating the xdc data for the linker; here's a minimal tool:
+# http://www.gknw.net/development/prgtools/mkxdc.zip
+MPKXDC = mkxdc
+
+# LIBARCH_U = $(shell $(AWK) 'BEGIN {print toupper(ARGV[1])}' $(LIBARCH))
+LIBARCH_L = $(shell $(AWK) 'BEGIN {print tolower(ARGV[1])}' $(LIBARCH))
+
+# Include the version info retrieved from curlver.h
+-include $(OBJDIR)/version.inc
+
+# Global flags for all compilers
+CFLAGS += $(OPT) -D$(DB) -DNETWARE -DHAVE_CONFIG_H -nostdinc
+
+ifeq ($(CC),mwccnlm)
+LD = mwldnlm
+LDFLAGS = -nostdlib $(OBJS) $(PRELUDE) $(LDLIBS) -o $@ -commandfile
+LIBEXT = lib
+CFLAGS += -gccinc -inline off -opt nointrinsics -proc 586
+CFLAGS += -relax_pointers
+#CFLAGS += -w on
+ifeq ($(LIBARCH),LIBC)
+ifeq ($(POSIXFL),1)
+ PRELUDE = $(NDK_LIBC)/imports/posixpre.o
+else
+ PRELUDE = $(NDK_LIBC)/imports/libcpre.o
+endif
+ CFLAGS += -align 4
+else
+ # PRELUDE = $(NDK_CLIB)/imports/clibpre.o
+ # to avoid the __init_* / __deinit_* whoes dont use prelude from NDK
+ PRELUDE = "$(MWCW_PATH)/libraries/runtime/prelude.obj"
+ # CFLAGS += -include "$(MWCW_PATH)/headers/nlm_clib_prefix.h"
+ CFLAGS += -align 1
+endif
+else
+LD = nlmconv
+LDFLAGS = -T
+LIBEXT = a
+CFLAGS += -m32
+CFLAGS += -fno-builtin -fno-strict-aliasing
+ifeq ($(findstring gcc,$(CC)),gcc)
+CFLAGS += -fpcc-struct-return
+endif
+CFLAGS += -Wall # -pedantic
+ifeq ($(LIBARCH),LIBC)
+ifeq ($(POSIXFL),1)
+ PRELUDE = $(NDK_LIBC)/imports/posixpre.gcc.o
+else
+ PRELUDE = $(NDK_LIBC)/imports/libcpre.gcc.o
+endif
+else
+ # PRELUDE = $(NDK_CLIB)/imports/clibpre.gcc.o
+ # to avoid the __init_* / __deinit_* whoes dont use prelude from NDK
+ # http://www.gknw.net/development/mk_nlm/gcc_pre.zip
+ PRELUDE = $(NDK_ROOT)/pre/prelude.o
+ CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h
+endif
+endif
+
+NDK_ROOT = $(NDKBASE)/ndk
+ifndef NDK_CLIB
+NDK_CLIB = $(NDK_ROOT)/nwsdk
+endif
+ifndef NDK_LIBC
+NDK_LIBC = $(NDK_ROOT)/libc
+endif
+ifndef NDK_LDAP
+NDK_LDAP = $(NDK_ROOT)/cldapsdk/netware
+endif
+CURL_INC = ../include
+CURL_LIB = ../lib
+
+INCLUDES = -I$(CURL_INC) -I$(CURL_LIB)
+
+ifeq ($(findstring -static,$(CFG)),-static)
+LINK_STATIC = 1
+endif
+ifeq ($(findstring -ares,$(CFG)),-ares)
+WITH_ARES = 1
+endif
+ifeq ($(findstring -rtmp,$(CFG)),-rtmp)
+WITH_RTMP = 1
+WITH_SSL = 1
+WITH_ZLIB = 1
+endif
+ifeq ($(findstring -ssh2,$(CFG)),-ssh2)
+WITH_SSH2 = 1
+WITH_SSL = 1
+WITH_ZLIB = 1
+endif
+ifeq ($(findstring -axtls,$(CFG)),-axtls)
+WITH_AXTLS = 1
+WITH_SSL =
+else
+ifeq ($(findstring -ssl,$(CFG)),-ssl)
+WITH_SSL = 1
+endif
+endif
+ifeq ($(findstring -zlib,$(CFG)),-zlib)
+WITH_ZLIB = 1
+endif
+ifeq ($(findstring -idn,$(CFG)),-idn)
+WITH_IDN = 1
+endif
+ifeq ($(findstring -spnego,$(CFG)),-spnego)
+WITH_SPNEGO = 1
+WITH_SSL = 1
+endif
+ifeq ($(findstring -metalink,$(CFG)),-metalink)
+WITH_METALINK = 1
+WITH_SSL = 1
+endif
+ifeq ($(findstring -ipv6,$(CFG)),-ipv6)
+ENABLE_IPV6 = 1
+endif
+
+ifdef LINK_STATIC
+ LDLIBS = $(CURL_LIB)/libcurl.$(LIBEXT)
+ifdef WITH_ARES
+ LDLIBS += $(LIBCARES_PATH)/libcares.$(LIBEXT)
+endif
+else
+ MODULES = libcurl.nlm
+ IMPORTS = @$(CURL_LIB)/libcurl.imp
+endif
+ifdef WITH_SSH2
+ # INCLUDES += -I$(LIBSSH2_PATH)/include
+ifdef LINK_STATIC
+ LDLIBS += $(LIBSSH2_PATH)/nw/libssh2.$(LIBEXT)
+else
+ MODULES += libssh2.nlm
+ IMPORTS += @$(LIBSSH2_PATH)/nw/libssh2.imp
+endif
+endif
+ifdef WITH_RTMP
+ # INCLUDES += -I$(LIBRTMP_PATH)
+ifdef LINK_STATIC
+ LDLIBS += $(LIBRTMP_PATH)/librtmp/librtmp.$(LIBEXT)
+endif
+endif
+ifdef WITH_SSL
+ # INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)
+ LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT)
+ LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT)
+ IMPORTS += GetProcessSwitchCount RunningProcess
+ifdef WITH_SPNEGO
+ # INCLUDES += -I$(FBOPENSSL_PATH)/include
+ LDLIBS += $(FBOPENSSL_PATH)/nw/fbopenssl.$(LIBEXT)
+endif
+else
+ifdef WITH_AXTLS
+ # INCLUDES += -I$(AXTLS_PATH)/inc
+ifdef LINK_STATIC
+ LDLIBS += $(AXTLS_PATH)/lib/libaxtls.$(LIBEXT)
+else
+ MODULES += libaxtls.nlm
+ IMPORTS += $(AXTLS_PATH)/lib/libaxtls.imp
+endif
+endif
+endif
+ifdef WITH_ZLIB
+ INCLUDES += -I$(ZLIB_PATH)
+ifdef LINK_STATIC
+ LDLIBS += $(ZLIB_PATH)/nw/$(LIBARCH)/libz.$(LIBEXT)
+else
+ MODULES += libz.nlm
+ IMPORTS += @$(ZLIB_PATH)/nw/$(LIBARCH)/libz.imp
+endif
+endif
+ifdef WITH_IDN
+ # INCLUDES += -I$(LIBIDN_PATH)/include
+ LDLIBS += $(LIBIDN_PATH)/lib/libidn.$(LIBEXT)
+endif
+ifdef WITH_METALINK
+ CFLAGS += -DUSE_METALINK
+ INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)
+ INCLUDES += -I$(LIBMETALINK_PATH)/include
+ LDLIBS += $(LIBMETALINK_PATH)/lib/libmetalink.$(LIBEXT)
+ifdef WITH_LIBEXPAT
+ ifeq ($(LIBARCH),LIBC)
+ IMPORTS += @$(LIBEXPAT_PATH)/imports/expatlbc.imp
+ MODULES += expatlbc
+ else
+ IMPORTS += @$(LIBEXPAT_PATH)/imports/expatlib.imp
+ MODULES += expatlib
+ endif
+else
+ifdef WITH_LIBXML2
+ IMPORTS += @$(LIBXML2_PATH)/lib/libxml2.imp
+ MODULES += libxml2
+endif
+endif
+endif
+
+ifeq ($(LIBARCH),LIBC)
+ INCLUDES += -I$(NDK_LIBC)/include
+ # INCLUDES += -I$(NDK_LIBC)/include/nks
+ # INCLUDES += -I$(NDK_LIBC)/include/winsock
+ CFLAGS += -D_POSIX_SOURCE
+else
+ INCLUDES += -I$(NDK_CLIB)/include/nlm
+ # INCLUDES += -I$(NDK_CLIB)/include
+endif
+ifndef DISABLE_LDAP
+ # INCLUDES += -I$(NDK_LDAP)/$(LIBARCH_L)/inc
+endif
+CFLAGS += $(INCLUDES)
+
+ifeq ($(MTSAFE),YES)
+ XDCOPT = -n
+endif
+ifeq ($(MTSAFE),NO)
+ XDCOPT = -u
+endif
+ifdef XDCOPT
+ XDCDATA = $(OBJDIR)/$(TARGET).xdc
+endif
+
+ifeq ($(findstring /sh,$(SHELL)),/sh)
+DL = '
+DS = /
+PCT = %
+#-include $(NDKBASE)/nlmconv/ncpfs.inc
+else
+DS = \\
+PCT = %%
+endif
+
+# Makefile.inc provides the CSOURCES and HHEADERS defines
+include Makefile.inc
+
+OBJX := $(patsubst %.c,$(OBJDIR)/%.o,$(notdir $(strip $(CURLX_ONES))))
+OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(strip $(CURL_CFILES)))
+ifndef LINK_STATIC
+OBJS += $(OBJX)
+endif
+
+vpath %.c $(CURL_LIB)
+
+all: prebuild $(TARGET).nlm
+
+prebuild: $(OBJDIR) $(OBJDIR)/version.inc
+
+$(OBJDIR)/%.o: %.c
+# @echo Compiling $<
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/version.inc: $(CURL_INC)/curl/curlver.h $(OBJDIR)
+ @echo Creating $@
+ @$(AWK) -f ../packages/NetWare/get_ver.awk $< > $@
+
+install: $(INSTDIR) all
+ @-$(CP) ../docs/$(TARGET).pdf $(INSTDIR)
+ @-$(CP) ../docs/$(TARGET).html $(INSTDIR)
+ @$(CP) $(TARGET).nlm $(INSTDIR)
+
+clean:
+ifeq "$(wildcard hugehelp.c.cvs)" "hugehelp.c.cvs"
+ -$(RM) hugehelp.c
+endif
+ -$(RM) -r $(OBJDIR)
+
+distclean vclean: clean
+ -$(RM) $(TARGET).nlm
+
+$(OBJDIR) $(INSTDIR):
+ @$(MKDIR) $@
+
+$(TARGET).nlm: $(OBJS) $(OBJDIR)/$(TARGET).def $(XDCDATA)
+ @echo Linking $@
+ @-$(RM) $@
+ @$(LD) $(LDFLAGS) $(OBJDIR)/$(TARGET).def
+
+$(OBJDIR)/%.xdc: Makefile.netware
+ @echo Creating $@
+ @$(MPKXDC) $(XDCOPT) $@
+
+$(OBJDIR)/%.def: Makefile.netware
+ @echo $(DL)# DEF file for linking with $(LD)$(DL) > $@
+ @echo $(DL)# Do not edit this file - it is created by make!$(DL) >> $@
+ @echo $(DL)# All your changes will be lost!!$(DL) >> $@
+ @echo $(DL)#$(DL) >> $@
+ @echo $(DL)copyright "$(COPYR)"$(DL) >> $@
+ @echo $(DL)description "$(DESCR)"$(DL) >> $@
+ @echo $(DL)version $(VERSION)$(DL) >> $@
+ifdef NLMTYPE
+ @echo $(DL)type $(NLMTYPE)$(DL) >> $@
+endif
+ifdef STACK
+ @echo $(DL)stack $(STACK)$(DL) >> $@
+endif
+ifdef SCREEN
+ @echo $(DL)screenname "$(SCREEN)"$(DL) >> $@
+else
+ @echo $(DL)screenname "DEFAULT"$(DL) >> $@
+endif
+ifneq ($(DB),NDEBUG)
+ @echo $(DL)debug$(DL) >> $@
+endif
+ @echo $(DL)threadname "$(TARGET)"$(DL) >> $@
+ifdef XDCDATA
+ @echo $(DL)xdcdata $(XDCDATA)$(DL) >> $@
+endif
+ifeq ($(LDRING),0)
+ @echo $(DL)flag_on 16$(DL) >> $@
+endif
+ifeq ($(LDRING),3)
+ @echo $(DL)flag_on 512$(DL) >> $@
+endif
+ifeq ($(LIBARCH),CLIB)
+ @echo $(DL)start _Prelude$(DL) >> $@
+ @echo $(DL)exit _Stop$(DL) >> $@
+ @echo $(DL)import @$(NDK_CLIB)/imports/clib.imp$(DL) >> $@
+ @echo $(DL)import @$(NDK_CLIB)/imports/threads.imp$(DL) >> $@
+ @echo $(DL)import @$(NDK_CLIB)/imports/nlmlib.imp$(DL) >> $@
+ @echo $(DL)import @$(NDK_CLIB)/imports/socklib.imp$(DL) >> $@
+ @echo $(DL)module clib$(DL) >> $@
+ifndef DISABLE_LDAP
+ @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapsdk.imp$(DL) >> $@
+ @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapssl.imp$(DL) >> $@
+# @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapx.imp$(DL) >> $@
+ @echo $(DL)module ldapsdk ldapssl$(DL) >> $@
+endif
+else
+ifeq ($(POSIXFL),1)
+ @echo $(DL)flag_on 4194304$(DL) >> $@
+endif
+ @echo $(DL)flag_on 64$(DL) >> $@
+ @echo $(DL)pseudopreemption$(DL) >> $@
+ifeq ($(findstring posixpre,$(PRELUDE)),posixpre)
+ @echo $(DL)start POSIX_Start$(DL) >> $@
+ @echo $(DL)exit POSIX_Stop$(DL) >> $@
+ @echo $(DL)check POSIX_CheckUnload$(DL) >> $@
+else
+ @echo $(DL)start _LibCPrelude$(DL) >> $@
+ @echo $(DL)exit _LibCPostlude$(DL) >> $@
+ @echo $(DL)check _LibCCheckUnload$(DL) >> $@
+endif
+ @echo $(DL)import @$(NDK_LIBC)/imports/libc.imp$(DL) >> $@
+ @echo $(DL)import @$(NDK_LIBC)/imports/netware.imp$(DL) >> $@
+ @echo $(DL)module libc$(DL) >> $@
+ifndef DISABLE_LDAP
+ @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapsdk.imp$(DL) >> $@
+ @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapssl.imp$(DL) >> $@
+# @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapx.imp$(DL) >> $@
+ @echo $(DL)module lldapsdk lldapssl$(DL) >> $@
+endif
+endif
+ifdef MODULES
+ @echo $(DL)module $(MODULES)$(DL) >> $@
+endif
+ifdef EXPORTS
+ @echo $(DL)export $(EXPORTS)$(DL) >> $@
+endif
+ifdef IMPORTS
+ @echo $(DL)import $(IMPORTS)$(DL) >> $@
+endif
+ifeq ($(findstring nlmconv,$(LD)),nlmconv)
+ @echo $(DL)input $(PRELUDE)$(DL) >> $@
+ @echo $(DL)input $(OBJS)$(DL) >> $@
+ifdef LDLIBS
+ @echo $(DL)input $(LDLIBS)$(DL) >> $@
+endif
+ @echo $(DL)output $(TARGET).nlm$(DL) >> $@
+endif
+
+hugehelp.c:
+ @echo Creating $@
+ @$(CP) hugehelp.c.cvs $@
+
+$(LIBCARES_PATH)/libcares.$(LIBEXT):
+ $(MAKE) -C $(LIBCARES_PATH) -f Makefile.netware lib
+
+
diff --git a/src/Makefile.vc6 b/src/Makefile.vc6
new file mode 100644
index 000000000..ac96c4ff0
--- /dev/null
+++ b/src/Makefile.vc6
@@ -0,0 +1,522 @@
+#***************************************************************************
+# _ _ ____ _
+# Project ___| | | | _ \| |
+# / __| | | | |_) | |
+# | (__| |_| | _ <| |___
+# \___|\___/|_| \_\_____|
+#
+# Copyright (C) 1999 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://curl.haxx.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+#***************************************************************************
+
+# All files in the Makefile.vc* series are generated automatically from the
+# one made for MSVC version 6. Alas, if you want to do changes to any of the
+# files and send back to the project, edit the version six, make your diff and
+# mail curl-users.
+
+#############################################################
+#
+## Makefile for building curl.exe with MSVC6
+## Use: nmake -f makefile.vc6 [release | debug] [CFG=release-ssl]
+## (default is release)
+## "nmake -f makefile.vc6 CFG=release-ssl" statically links OpenSSL
+## into curl.exe producing a standalone SSL-enabled executable.
+##
+#
+#############################################################
+
+PROGRAM_NAME = curl.exe
+
+# -------------------------------------------
+# Verify that current subdir is curl's 'src'
+# -------------------------------------------
+
+!IF ! EXIST(.\tool_main.c)
+! MESSAGE Can not process this makefile from outside of curl's 'src' subdirectory.
+! MESSAGE Change to curl's 'src' subdirectory, and try again.
+! ERROR See previous message.
+!ENDIF
+
+# ------------------------------------------------
+# Makefile.msvc.names provides libcurl file names
+# ------------------------------------------------
+
+!INCLUDE ..\Makefile.msvc.names
+
+
+
+!IFNDEF OPENSSL_PATH
+OPENSSL_PATH = ../../openssl-0.9.8x
+!ENDIF
+
+!IFNDEF ZLIB_PATH
+ZLIB_PATH = ../../zlib-1.2.7
+!ENDIF
+
+!IFNDEF MACHINE
+MACHINE = X86
+!ENDIF
+
+# USE_WINDOWS_SSPI uses windows libraries to allow NTLM authentication
+# without an openssl installation and offers the ability to authenticate
+# using the "current logged in user". Since at least with MSVC6 the sspi.h
+# header is broken it is either required to install the Windows SDK,
+# or to fix sspi.h with adding this define at the beginning of sspi.h:
+# #define FreeCredentialHandle FreeCredentialsHandle
+#
+# If, for some reason the Windows SDK is installed but not installed
+# in the default location, you can specify WINDOWS_SDK_PATH.
+# It can be downloaded from:
+# http://www.microsoft.com/msdownload/platformsdk/sdkupdate/
+
+# WINDOWS_SSPI = 1
+
+!IFDEF WINDOWS_SSPI
+!IFNDEF WINDOWS_SDK_PATH
+WINDOWS_SDK_PATH = "$(PROGRAMFILES)\Microsoft SDK"
+!ENDIF
+!ENDIF
+
+########################################################
+## Nothing more to do below this line!
+
+ZLIB_CFLAGS = /DHAVE_ZLIB_H /DHAVE_ZLIB /DHAVE_LIBZ /I "$(ZLIB_PATH)"
+ZLIB_LFLAGS = "/LIBPATH:$(ZLIB_PATH)"
+ZLIB_LIBS = zlib.lib
+ZLIB_IMP_LIBS = zdll.lib
+
+SSL_CFLAGS = /DUSE_SSLEAY
+SSL_LFLAGS = /LIBPATH:"$(OPENSSL_PATH)/out32"
+SSL_IMP_LFLAGS = /LIBPATH:"$(OPENSSL_PATH)/out32dll"
+SSL_LIBS = libeay32.lib ssleay32.lib gdi32.lib user32.lib
+
+# Runtime library configuration
+RTLIB = /MD
+RTLIBD = /MDd
+
+!IF "$(RTLIBCFG)" == "static"
+RTLIB = /MT
+RTLIBD = /MTd
+!ENDIF
+
+## Release
+CCR = cl.exe $(RTLIB) /O2 /DNDEBUG
+LINKR = link.exe /incremental:no /libpath:"../lib"
+RCR = rc.exe /dDEBUGBUILD=0
+
+## Debug
+CCD = cl.exe $(RTLIBD) /Gm /ZI /Od /D_DEBUG /GZ
+LINKD = link.exe /incremental:yes /debug /libpath:"../lib"
+RCD = rc.exe /dDEBUGBUILD=1
+
+CFLAGS = /I../lib /I../include /nologo /W3 /GX /DWIN32 /YX /FD /c /D_BIND_TO_CURRENT_VCLIBS_VERSION=1
+LFLAGS = /nologo /out:$(PROGRAM_NAME) /subsystem:console /machine:$(MACHINE)
+RESFLAGS = /i../include
+
+# This manifest thing is for VC8, enabled by the maketgz script that
+# builds the VC8 version of this makefile. Left commented out in the VC6
+# version!
+#MANIFESTTOOL = mt -manifest $(PROGRAM_NAME).manifest -outputresource:$(PROGRAM_NAME);1
+
+!IFDEF WINDOWS_SSPI
+CFLAGS = $(CFLAGS) /DUSE_WINDOWS_SSPI /I$(WINDOWS_SDK_PATH)\include
+!ENDIF
+
+RELEASE_OBJS= \
+ hugehelpr.obj \
+ nonblockr.obj \
+ rawstrr.obj \
+ strtoofftr.obj \
+ tool_binmoder.obj \
+ tool_bnamer.obj \
+ tool_cb_dbgr.obj \
+ tool_cb_hdrr.obj \
+ tool_cb_prgr.obj \
+ tool_cb_rear.obj \
+ tool_cb_seer.obj \
+ tool_cb_wrtr.obj \
+ tool_cfgabler.obj \
+ tool_convertr.obj \
+ tool_dirhier.obj \
+ tool_doswinr.obj \
+ tool_easysrcr.obj \
+ tool_formparser.obj \
+ tool_getparamr.obj \
+ tool_getpassr.obj \
+ tool_helpr.obj \
+ tool_helpersr.obj \
+ tool_homedirr.obj \
+ tool_libinfor.obj \
+ tool_mainr.obj \
+ tool_metalinkr.obj \
+ tool_mfilesr.obj \
+ tool_msgsr.obj \
+ tool_operater.obj \
+ tool_operhlpr.obj \
+ tool_panykeyr.obj \
+ tool_paramhlpr.obj \
+ tool_parsecfgr.obj \
+ tool_setoptr.obj \
+ tool_sleepr.obj \
+ tool_urlglobr.obj \
+ tool_utilr.obj \
+ tool_vmsr.obj \
+ tool_writeenvr.obj \
+ tool_writeoutr.obj \
+ tool_xattrr.obj \
+ curlr.res
+
+DEBUG_OBJS= \
+ hugehelpd.obj \
+ nonblockd.obj \
+ rawstrd.obj \
+ strtoofftd.obj \
+ tool_binmoded.obj \
+ tool_bnamed.obj \
+ tool_cb_dbgd.obj \
+ tool_cb_hdrd.obj \
+ tool_cb_prgd.obj \
+ tool_cb_read.obj \
+ tool_cb_seed.obj \
+ tool_cb_wrtd.obj \
+ tool_cfgabled.obj \
+ tool_convertd.obj \
+ tool_dirhied.obj \
+ tool_doswind.obj \
+ tool_easysrcd.obj \
+ tool_formparsed.obj \
+ tool_getparamd.obj \
+ tool_getpassd.obj \
+ tool_helpd.obj \
+ tool_helpersd.obj \
+ tool_homedird.obj \
+ tool_libinfod.obj \
+ tool_maind.obj \
+ tool_metalinkd.obj \
+ tool_mfilesd.obj \
+ tool_msgsd.obj \
+ tool_operated.obj \
+ tool_operhlpd.obj \
+ tool_panykeyd.obj \
+ tool_paramhlpd.obj \
+ tool_parsecfgd.obj \
+ tool_setoptd.obj \
+ tool_sleepd.obj \
+ tool_urlglobd.obj \
+ tool_utild.obj \
+ tool_vmsd.obj \
+ tool_writeenvd.obj \
+ tool_writeoutd.obj \
+ tool_xattrd.obj \
+ curld.res
+
+#################################################
+# If CFG not specified, use static libs
+
+CFLAGS = $(CFLAGS) /DCURL_STATICLIB
+LINKLIBS = $(LIBCURL_STA_LIB_REL)
+LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG)
+
+#################################################
+# release dynamic library
+
+!IF "$(CFG)" == "release-dll"
+LINKLIBS = $(LIBCURL_IMP_LIB_REL)
+LINKLIBS_DEBUG = $(LIBCURL_IMP_LIB_DBG)
+!ENDIF
+
+#################################################
+# release static library with zlib
+
+!IF "$(CFG)" == "release-zlib"
+CFLAGS = $(CFLAGS) $(ZLIB_CFLAGS) /DCURL_STATICLIB
+LINKLIBS = $(LIBCURL_STA_LIB_REL) $(ZLIB_LIBS)
+LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(ZLIB_LIBS)
+LFLAGS = $(LFLAGS) $(ZLIB_LFLAGS)
+!ENDIF
+
+#################################################
+# release static library with ssl
+
+!IF "$(CFG)" == "release-ssl"
+CFLAGS = $(CFLAGS) $(SSL_CFLAGS) /DCURL_STATICLIB
+LINKLIBS = $(LIBCURL_STA_LIB_REL) $(SSL_LIBS)
+LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(SSL_LIBS)
+LFLAGS = $(LFLAGS) $(SSL_LFLAGS)
+!ENDIF
+
+#################################################
+# release dynamic library with dynamic ssl
+
+!IF "$(CFG)" == "release-dll-ssl-dll"
+CFLAGS = $(CFLAGS) $(SSL_CFLAGS)
+LINKLIBS = $(LIBCURL_IMP_LIB_REL) $(SSL_LIBS)
+LINKLIBS_DEBUG = $(LIBCURL_IMP_LIB_DBG) $(SSL_LIBS)
+LFLAGS = $(LFLAGS) $(SSL_IMP_LFLAGS)
+!ENDIF
+
+#################################################
+# release static library with ssl and zlib
+
+!IF "$(CFG)" == "release-ssl-zlib"
+CFLAGS = $(CFLAGS) $(SSL_CFLAGS) $(ZLIB_CFLAGS) /DCURL_STATICLIB
+LINKLIBS = $(LIBCURL_STA_LIB_REL) $(SSL_LIBS) $(ZLIB_LIBS)
+LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(SSL_LIBS) $(ZLIB_LIBS)
+LFLAGS = $(LFLAGS) $(SSL_LFLAGS) $(ZLIB_LFLAGS)
+!ENDIF
+
+#################################################
+# release static library with dynamic ssl
+
+!IF "$(CFG)" == "release-ssl-dll"
+CFLAGS = $(CFLAGS) $(SSL_CFLAGS) /DCURL_STATICLIB
+LINKLIBS = $(LIBCURL_STA_LIB_REL) $(SSL_LIBS)
+LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(SSL_LIBS)
+LFLAGS = $(LFLAGS) $(SSL_IMP_LFLAGS)
+!ENDIF
+
+#################################################
+# release static library with dynamic zlib
+
+!IF "$(CFG)" == "release-zlib-dll"
+CFLAGS = $(CFLAGS) $(ZLIB_CFLAGS) /DCURL_STATICLIB
+LINKLIBS = $(LIBCURL_STA_LIB_REL) $(ZLIB_IMP_LIBS)
+LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(ZLIB_IMP_LIBS)
+LFLAGS = $(LFLAGS) $(ZLIB_LFLAGS)
+!ENDIF
+
+#################################################
+# release dynamic library with dynamic zlib
+
+!IF "$(CFG)" == "release-dll-zlib-dll"
+CFLAGS = $(CFLAGS) $(ZLIB_CFLAGS)
+LINKLIBS = $(LIBCURL_IMP_LIB_REL) $(ZLIB_IMP_LIBS)
+LINKLIBS_DEBUG = $(LIBCURL_IMP_LIB_DBG) $(ZLIB_IMP_LIBS)
+LFLAGS = $(LFLAGS) $(ZLIB_LFLAGS)
+!ENDIF
+
+#################################################
+# release static library with dynamic ssl and dynamic zlib
+
+!IF "$(CFG)" == "release-ssl-dll-zlib-dll"
+CFLAGS = $(CFLAGS) $(SSL_CFLAGS) $(ZLIB_CFLAGS) /DCURL_STATICLIB
+LINKLIBS = $(LIBCURL_STA_LIB_REL) $(SSL_LIBS) $(ZLIB_IMP_LIBS)
+LINKLIBS_DEBUG = $(LIBCURL_STA_LIB_DBG) $(SSL_LIBS) $(ZLIB_IMP_LIBS)
+LFLAGS = $(LFLAGS) $(SSL_IMP_LFLAGS) $(ZLIB_LFLAGS)
+!ENDIF
+
+#################################################
+# release dynamic library with dynamic ssl and dynamic zlib
+
+!IF "$(CFG)" == "release-dll-ssl-dll-zlib-dll"
+CFLAGS = $(CFLAGS) $(SSL_CFLAGS) $(ZLIB_CFLAGS)
+LINKLIBS = $(LIBCURL_IMP_LIB_REL) $(SSL_LIBS) $(ZLIB_IMP_LIBS)
+LINKLIBS_DEBUG = $(LIBCURL_IMP_LIB_DBG) $(SSL_LIBS) $(ZLIB_IMP_LIBS)
+LFLAGS = $(LFLAGS) $(SSL_IMP_LFLAGS) $(ZLIB_LFLAGS)
+!ENDIF
+
+
+LINKLIBS = $(LINKLIBS) ws2_32.lib wldap32.lib advapi32.lib
+LINKLIBS_DEBUG = $(LINKLIBS_DEBUG) ws2_32.lib wldap32.lib advapi32.lib
+
+all : release
+
+release: $(RELEASE_OBJS)
+ $(LINKR) $(LFLAGS) $(LINKLIBS) $(RELEASE_OBJS)
+ $(MANIFESTTOOL)
+
+debug: $(DEBUG_OBJS)
+ $(LINKD) $(LFLAGS) $(LINKLIBS_DEBUG) $(DEBUG_OBJS)
+ $(MANIFESTTOOL)
+
+## Release
+hugehelpr.obj: hugehelp.c
+ $(CCR) $(CFLAGS) /Zm200 /Fo"$@" hugehelp.c
+nonblockr.obj: ../lib/nonblock.c
+ $(CCR) $(CFLAGS) /Fo"$@" ../lib/nonblock.c
+rawstrr.obj: ../lib/rawstr.c
+ $(CCR) $(CFLAGS) /Fo"$@" ../lib/rawstr.c
+strtoofftr.obj: ../lib/strtoofft.c
+ $(CCR) $(CFLAGS) /Fo"$@" ../lib/strtoofft.c
+tool_binmoder.obj: tool_binmode.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_binmode.c
+tool_bnamer.obj: tool_bname.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_bname.c
+tool_cb_dbgr.obj: tool_cb_dbg.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_dbg.c
+tool_cb_hdrr.obj: tool_cb_hdr.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_hdr.c
+tool_cb_prgr.obj: tool_cb_prg.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_prg.c
+tool_cb_rear.obj: tool_cb_rea.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_rea.c
+tool_cb_seer.obj: tool_cb_see.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_see.c
+tool_cb_wrtr.obj: tool_cb_wrt.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_wrt.c
+tool_cfgabler.obj: tool_cfgable.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cfgable.c
+tool_convertr.obj: tool_convert.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_convert.c
+tool_dirhier.obj: tool_dirhie.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_dirhie.c
+tool_doswinr.obj: tool_doswin.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_doswin.c
+tool_easysrcr.obj: tool_easysrc.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_easysrc.c
+tool_formparser.obj: tool_formparse.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_formparse.c
+tool_getparamr.obj: tool_getparam.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_getparam.c
+tool_getpassr.obj: tool_getpass.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_getpass.c
+tool_helpr.obj: tool_help.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_help.c
+tool_helpersr.obj: tool_helpers.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_helpers.c
+tool_homedirr.obj: tool_homedir.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_homedir.c
+tool_libinfor.obj: tool_libinfo.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_libinfo.c
+tool_mainr.obj: tool_main.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_main.c
+tool_metalinkr.obj: tool_metalink.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_metalink.c
+tool_mfilesr.obj: tool_mfiles.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_mfiles.c
+tool_msgsr.obj: tool_msgs.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_msgs.c
+tool_operater.obj: tool_operate.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_operate.c
+tool_operhlpr.obj: tool_operhlp.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_operhlp.c
+tool_panykeyr.obj: tool_panykey.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_panykey.c
+tool_paramhlpr.obj: tool_paramhlp.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_paramhlp.c
+tool_parsecfgr.obj: tool_parsecfg.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_parsecfg.c
+tool_setoptr.obj: tool_setopt.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_setopt.c
+tool_sleepr.obj: tool_sleep.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_sleep.c
+tool_urlglobr.obj: tool_urlglob.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_urlglob.c
+tool_utilr.obj: tool_util.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_util.c
+tool_vmsr.obj: tool_vms.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_vms.c
+tool_writeenvr.obj: tool_writeenv.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_writeenv.c
+tool_writeoutr.obj: tool_writeout.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_writeout.c
+tool_xattrr.obj: tool_xattr.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_xattr.c
+curlr.res : curl.rc
+ $(RCR) $(RESFLAGS) /Fo"$@" curl.rc
+
+## Debug
+hugehelpd.obj: hugehelp.c
+ $(CCD) $(CFLAGS) /Zm200 /Fo"$@" hugehelp.c
+nonblockd.obj: ../lib/nonblock.c
+ $(CCD) $(CFLAGS) /Fo"$@" ../lib/nonblock.c
+rawstrd.obj: ../lib/rawstr.c
+ $(CCD) $(CFLAGS) /Fo"$@" ../lib/rawstr.c
+strtoofftd.obj: ../lib/strtoofft.c
+ $(CCD) $(CFLAGS) /Fo"$@" ../lib/strtoofft.c
+tool_binmoded.obj: tool_binmode.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_binmode.c
+tool_bnamed.obj: tool_bname.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_bname.c
+tool_cb_dbgd.obj: tool_cb_dbg.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_dbg.c
+tool_cb_hdrd.obj: tool_cb_hdr.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_hdr.c
+tool_cb_prgd.obj: tool_cb_prg.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_prg.c
+tool_cb_read.obj: tool_cb_rea.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_rea.c
+tool_cb_seed.obj: tool_cb_see.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_see.c
+tool_cb_wrtd.obj: tool_cb_wrt.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_wrt.c
+tool_cfgabled.obj: tool_cfgable.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cfgable.c
+tool_convertd.obj: tool_convert.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_convert.c
+tool_dirhied.obj: tool_dirhie.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_dirhie.c
+tool_doswind.obj: tool_doswin.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_doswin.c
+tool_easysrcd.obj: tool_easysrc.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_easysrc.c
+tool_formparsed.obj: tool_formparse.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_formparse.c
+tool_getparamd.obj: tool_getparam.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_getparam.c
+tool_getpassd.obj: tool_getpass.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_getpass.c
+tool_helpd.obj: tool_help.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_help.c
+tool_helpersd.obj: tool_helpers.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_helpers.c
+tool_homedird.obj: tool_homedir.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_homedir.c
+tool_libinfod.obj: tool_libinfo.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_libinfo.c
+tool_maind.obj: tool_main.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_main.c
+tool_metalinkd.obj: tool_metalink.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_metalink.c
+tool_mfilesd.obj: tool_mfiles.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_mfiles.c
+tool_msgsd.obj: tool_msgs.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_msgs.c
+tool_operated.obj: tool_operate.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_operate.c
+tool_operhlpd.obj: tool_operhlp.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_operhlp.c
+tool_panykeyd.obj: tool_panykey.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_panykey.c
+tool_paramhlpd.obj: tool_paramhlp.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_paramhlp.c
+tool_parsecfgd.obj: tool_parsecfg.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_parsecfg.c
+tool_setoptd.obj: tool_setopt.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_setopt.c
+tool_sleepd.obj: tool_sleep.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_sleep.c
+tool_urlglobd.obj: tool_urlglob.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_urlglob.c
+tool_utild.obj: tool_util.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_util.c
+tool_vmsd.obj: tool_vms.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_vms.c
+tool_writeenvd.obj: tool_writeenv.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_writeenv.c
+tool_writeoutd.obj: tool_writeout.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_writeout.c
+tool_xattrd.obj: tool_xattr.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_xattr.c
+curld.res : curl.rc
+ $(RCD) $(RESFLAGS) /Fo"$@" curl.rc
+
+clean:
+ @-erase $(PROGRAM_NAME) 2> NUL
+ @-erase $(RELEASE_OBJS) 2> NUL
+ @-erase $(DEBUG_OBJS) 2> NUL
+ @-erase *.idb 2> NUL
+ @-erase *.pdb 2> NUL
+ @-erase *.pch 2> NUL
+ @-erase *.ilk 2> NUL
diff --git a/src/curl.rc b/src/curl.rc
new file mode 100644
index 000000000..3db59bd3c
--- /dev/null
+++ b/src/curl.rc
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include <winver.h>
+#include "tool_version.h"
+
+LANGUAGE 0x09,0x01
+
+#define RC_VERSION CURL_VERSION_MAJOR, CURL_VERSION_MINOR, CURL_VERSION_PATCH, 0
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION RC_VERSION
+ PRODUCTVERSION RC_VERSION
+ FILEFLAGSMASK 0x3fL
+#if defined(DEBUGBUILD) || defined(_DEBUG)
+ FILEFLAGS 1
+#else
+ FILEFLAGS 0
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "cURL, http://curl.haxx.se/\0"
+ VALUE "FileDescription", "The cURL executable\0"
+ VALUE "FileVersion", CURL_VERSION "\0"
+ VALUE "InternalName", "curl\0"
+ VALUE "OriginalFilename", "curl.exe\0"
+ VALUE "ProductName", "The cURL executable\0"
+ VALUE "ProductVersion", CURL_VERSION "\0"
+ VALUE "LegalCopyright", "© " CURL_COPYRIGHT "\0"
+ VALUE "License", "http://curl.haxx.se/docs/copyright.html\0"
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/hugehelp.c.cvs b/src/hugehelp.c.cvs
new file mode 100644
index 000000000..7cecf64db
--- /dev/null
+++ b/src/hugehelp.c.cvs
@@ -0,0 +1,6 @@
+#include "tool_setup.h"
+#include "hugehelp.h"
+void hugehelp(void)
+{
+ puts ( "This is a silly replacement for the actual file.");
+}
diff --git a/src/hugehelp.h b/src/hugehelp.h
new file mode 100644
index 000000000..698c916a6
--- /dev/null
+++ b/src/hugehelp.h
@@ -0,0 +1,28 @@
+#ifndef HEADER_CURL_HUGEHELP_H
+#define HEADER_CURL_HUGEHELP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+void hugehelp(void);
+
+#endif /* HEADER_CURL_HUGEHELP_H */
diff --git a/src/macos/MACINSTALL.TXT b/src/macos/MACINSTALL.TXT
new file mode 100644
index 000000000..17da13325
--- /dev/null
+++ b/src/macos/MACINSTALL.TXT
@@ -0,0 +1 @@
+MACOS (not MACOS X) =================== This is the first attempt at porting cURL to MacOS. http, ftp, dict and telnet seems to work fine, other protocols and advanced features have not been all tested. This port is heavily based on the GUSI library from Matthias Neeracher. GUSI (Grand Unified Socket Interface) is a POSIX/Pthreads/Sockets library bringing some of the comforts of UNIX 98 to traditional MacOS. The latest GUSI release can be downloaded from sourceforge at <http://sourceforge.net/projects/gusi/> I have also write a few functions to help port UNIX applications to MacOS. These functions are part of the GUSI Extra library that can be downloaded at <http://perso.wanadoo.fr/ela/resources.html#gusiextra> OpenSSL support is still experimental but I hope to deliver a version including SSL soon. cURL for MacOS requires using the CodeWarrior compiler from Metrowerks. First download GUSI, GUSI Extra and cURL. Access paths have been setup so that GUSI, GUSI Extra and cURL directories should have the same parent directory. Follow the instructions in GUSI Extra "readme.txt" mainly the ones related to SIOUX and GUSI patches. If you do not apply these patches curl will not behave correctly. In the 'curl/src/macos' directory, decode "curl.mcp.xml.sit.hqx" (This is a stuffit binhexed file) From the CodeWarrior IDE, import 'curl/src/macos/curl.xml', adjust the access paths if required. Then you should be able to build: - the libcurl libraries for PPC and 68K. - the curl application (also available for PPC and 68K) which is the command line version of cURL. If the file "hugehelp.c" is missing rename "curl/src/hugehelp.c.cvs" to "hugehelp.c" and make sure its file type is 'TEXT' \ No newline at end of file
diff --git a/src/macos/curl.mcp.xml.sit.hqx b/src/macos/curl.mcp.xml.sit.hqx
new file mode 100644
index 000000000..01650b9a1
--- /dev/null
+++ b/src/macos/curl.mcp.xml.sit.hqx
@@ -0,0 +1 @@
+(This file must be converted with BinHex 4.0) :%'0eFQ`ZE@0`,RKYE#jcDA3!8dP8090*9#%!N!3F@`#3")EF8h4eCQC*G#!SBbN a16Nh,6)`-$%J3@aKC'4TEL"6HA0dC@ec,#"*EQ-Z,#"SG(4`1Lm[Gj!$,Q&XB@4 ND@jcHA-ZBfpY,e0dG@CQ5A3[$3SD!!83!!!F@`#3!h)!!3#3!h)0,`fPT9*PFf9 bGQ9NTD8!TC!%!3!!2!!3Z$+T+EJbU5N!N!d-['F!"*UP!!!E'J#3"!m!Bh9bE#j YBh!ZH'eX!!%`!P4&@&4$9dP&!3$rN!3!N!U!!*!*!CS!N!0K!*!%$`"#`G6)[bB "`A,RBHAV3f@ZJUhAq'5,9!EjE+@0l9R9ECKR4kTRRh2Tr@@VMJ"@0,FaU4R&FMa LBT)4LbVeb+BC%jqHQQI4[fPBGXP3'T4BeHdDm#H-`9$4'EUJEJ186cE)3X(8K-U 1KiJ4+5-HVi0DI[@5XBTQHb300K2--ZQmjPHEfdA)NhXMSJc'A+@kemq4P`'SeCB TD8QEYXMK8Kk4YZRkc1,G%m39"[dp8Zmc'[eKd,jpTVh555HQXd2`S9"KrGB`laE (r+!)8r8DP'9kbYVQeY-aSjVQRA2k-`'2pqTr9EP6Z&H-%4eK4@qp1Z(fDAd1&`A H1IYG&T86QUHmp*%cdr$@G4fJrQ[9'8p)f"FPKmMQH6!kGBGeTA5Im1Pp*(P69-* b8ld+I'KQIH`@CNfcIEGE&Zbb`3f,4IkZ#4Ve"2%R-a#MLYefeG"*FSMj,RD`aaE DHh6$h8hF"r`SK84RjI*$KFfI&J3ZTk"r!J2$Nr#%K(IA803e(bAG645j1231E'$ C5$(Nr9Z2LZbqJPSH&9[h1(,+e"8!I$4XKrIeH6Y"")PlSQG2V4#-hZAbb2jBT25 (IUG-bFQ+0[bbfAlrpIDlpCradaS5G(*4d%[i*ISQ&5*3e$NVT#A+!Y3P%V*@HX9 6AGI"h1N`D@lj56PX8fB95NekUL&lk'15a*Z(38rC`Ii%$Y$E-A"!QfHG(Ed)Uhd $e&Ckrm4jfVikK&j$D[%H)*lGX!FUK'&[Ck*%#lJUT9qiT13X#T4mK2)e"`%-JFe )*)Sa9b+92'@Gb8N6d9E+kJ#VEA(c6+d`%E82FXcNKJYM'a,FD@Jf-Bhe0i+B2b' 4,T!!lq1IYLpFITlMfGiYPc0f$6,+MDV5TI9#X-SpJhU%)Fb8cp2EjaJ6Y-)DC*f e'FGC5B'BdQV'H!@cS`XJID*-@m3!EFmNq*Ve20Pc0%pLrF4I`MH*iE!bAI`TJ6f fIkZ$4)P"bTla%@'ZL"8pmd(L(R3XEa8KPe@FkheL$l%E1UF89BS&afbE`RN#pXJ IUFD+"e#6RG6PSV[,G0B8l,Ipa2UU$4a@eA6jr+8Y,jkA1f9)d0!)UcD8pc1PCaS $4e#PcC8bCKD'Ar-2Yr"-%XLQh@AF!9p6rj`FhAk@,R*F(2h!LB#ca(F'im+pi,L Bf4LJV+icK26r2XR2)q9fr#K3PQ3PU)3V#9KqDVJL&pEb*`f)lAAq9FdpFU[$8N6 H43&)*h$BNrd0,c(!ICCA2Nh-i-b#,A9)Dq6b0QXcb4Cb)HG0c,H"E8"bQ0V82+K (6bpND%LUfp6S(mNAhkhHBJTdab-6GA&I%2cqe4`NjKlSpKDmI6m!h0,h!`LC-2j pCCGeT6#1Y62eS"hVZBAlj!YPi8DS1XV14b!3d)r5Z1C(*KTB'Df3!+cZN!#aJMU am2DQK54epTl55RJcT[d$'Q5Me1@)lDI#N6S,Rb-#2%BpdZePl2&DZb9GH)-0FR` 3N!!5&mlD,Sp)"5ZC2f@E-bpUflPTaUfFJ4mZUlcp#`iNNNl#eBaVI1&m0!dP'F[ lT`UUYVZpKX&HPmBMVf"+'fS0*6pRfA+HccXLd0PXk",eKDrh`@MYIGqm(MRcMcP UCb#C$m'[dhBrb438Hbh4+bDe&0"BSF1P+PPP4@i`%iP22P9ibJHTcBXRN5!leUL LkN%bVNT!r-qGI('DMAp8jc1e[eH9VBp1+DSk0V(-aMaJD(6FHQ+T'%'h8"e3LeY *2ldFPa@Tem)!l+PBLXN#idPfFC0i-V-9Ed2X@hEhCC!!e2J+JDccb1@@XE`Ch+V @!I1YF"Jf&8Kc*-A[5BT"cFJ3I8rP#Vb#NHYS+"%q25(pP2,aD$5KBV4"&PiN--c f!&h'b,[%ZDE0!j&ZY32dZD3h)p'VEr2p@kU8c8kU,K'lh$A8,)`efrhRPmImIpI YXG)SXje6-1Z$'lrlYNl#ECVlA2V[1h9Ej6X"Q-(LA%P65$-Ka92rah%dQmeF#KH (%CE56(aEpX$BKjEHj(6mN!"l3iEi(2#eJXU2$BHK`913!#8U6q3!&-VfilRY05# +CbP+)RJR0D'943,GI+$+0I0+'SNaNUMBZ[q4'kLpb*c)iGMP,'c'hFQc1B6@@J6 fXPPfGrc`"VaZDc5@lD1*@AIr'1UT5C'NI$HV@!e*U##m)62YSNd$`'p*J1[@ZVM 5D'GRTkrhF6"1D9-DV'2YVR*$RV,I`+QmTjICq92DT-f+SL1lD&kp)C8`64h*aY* AaJiFNQBGVU!$p6A1-m-e*1L9Iic!B!lQ,rZIkda"cB%TJ`U*0QP,'JVEhkFUFU& (X5K4`r3eG5!0T0`KfYQ6-I-E-mUbb&1TIGYrd"X"EXL$@U!J)EB+%q8mMd,dFeJ fLGJA5!N*4MXRSYfk8"8Vp9RY*4rXaR0dQ"3d!1R%CAQZRaPE1*MZ&DHdelBBaaA (CTA1k$H!##ZMT'i$kB0JJPc9Y"5Em&M)DRM*#SIahMpP`2T[3F,Sr2JX9E@,U5L 10Sdd1Y(qAG#,G'hX$PibcN@!,X`qX*,'eM#B)#S*k1PLLI*REMpB"UmhHT-j!0& TG)jc$@3BLI"em*jDf-B%qLmRR$,BQ1q)YN!*Q1ZNVH,YL#f$!C3-1#@Lch3a2+D 1S3dIq-1a[1C*E$*P+KPQG`THP&p'TQ$JJ-*$cK9F03c3F-aJGGic8i,3hd[fAQ( X2Zr!KU)Rlj!!cer8P'[-pmXiEG4ETUADfi2e!+XIM"@%f)[i)Ikd3c!4jR!-4ar q1T6*aH(Xp6eP)1"JRKV00!kq!BaZa-p*GA93QrN2e@l5U!bDcH)QqRTh9BT04b$ 5Yml1!p$+q9ILbSc)r+'IfN,jLH0'9S)Z+ji4P'1GBK9MHCmrhF8AVC(Xmm"IHl# QFBJ"3PC,19FjeHrVT3AV%qCIqAh1VJm(G,#b$Gh-aRS@jXNFTGXV8@2Eq&L#U%L bf**dKC),j0c9*P0&V!XPRpA0'`jEQG1PDJ+Zdb`[PpRLe34(EcHI-CPm54(VIbE 2J3S%q'`"i`+,HjI3D&@MmVRC5ffqFSVlc[1eQP`@)$eHGrSTSGA@,fc&Yd%c#-[ c`N5)bZ%5b!`+QA-C%YBp[NpG`fMrU'VklXR-he$9jRbE5pBEJR2GeER[mN'1,[` *5HDBYJFl#DN&kKi#mVHiL2@'H4Lb-%(#jb5!e"`RQeJJPfD*L#l$'($NZ1*53#4 P"Z19[8kVVN86PN0#LLPpq&`6QI1)ZR-h3b"[H'qCf&q%J1$CRiFD6AhC'iAdA!5 &9qaeYeVcr,1k'F2P%TlIY-mjXqRIMK+"1cJjQ1[ad0mTG53!aa[IQhlKS@)N-(a pUJ$DahNB2HZ[!!fJ,p(-ACep@IGH86&XYZf#UZd`6HTD`e66bA,VjkUkQpeq)%J hajLPmXp(SipKb*'k%k1f[e'0!D&Sh80Q"$BH&jiJb+SEbpTbQBkE2Qp,5[hLS@1 1pUZ(*&)`(+D+RH8$Z0,+br4iTZJ2rZVP,UC!FP8[XHa#3+"aHC!!DMcpKpFDeIe D%2`@$YX20DB&iIcJUS-R%eCPc4&MSE2f3qfA9IJK5I@,R4403FVlTR'JKYF'NBr eC`jcaFi8Bl$9bp,K,TCp"cJ33fq@Z6`!DldUA,C8J[(2MaI2,p!`$5YT12Mei`2 kEK")F$6(J8GAiLMFaTiMqpE8KiZGrrk"D3Fi#8(4*fVmGK4GIb9Pb9N,%Qh2V&b G`4BR#1B@ZrmSF@DdRU#!!i64LJXc9abPYpjfa+I*FSZ(&IkqF2,@5XqlSfe(pJ5 @FBNcIm6`B$SBQ19pA0k8'bmMac8kRP[Q#l4qV9P3ibU$dmlE'[@*Dj1JGRJe4[Z 5M#`*0UYGpeTAFQV4)hc"Frq0Qe88T#fG+YrEd%GD5VaN8ee69)@GJLMaCTYZJ$h Y`PmD[A8fB#4GP0TV(G5&@%i-DBILl&5HUC*fk#qhfiL-VdMPEK`@*G5aB'3@1DI `Gmq!%mJhD-m-E@ei1#pf)H!Y)#hdYf5,Kre61KKr6-k+iC&[6#!,*8aC4V,dBda *G-Ea,kcp`EQYmI)q(TSXdpT[&6NmmVela*&ZrNk#!a*Ek1U9e(A-C#MTiFrU*8# GRIPS(IG0NC0@D@C,ef!3$-V,f1MmeU$hMNGflfPjdA1l$m'dhT6mE$5k,&09Rk* 35$B&A8hc`Q,f[MCL'()&ZSp9"F43Y6Gp$d@GQ1*-IFE)fQ`!Gl+4bY!)4&ME!i1 S(e$jM(!B0$aPZUklAZC&R6Q$q(JE0b`QVJ8l2ELL'2i"i$m4hNQq3$S*@r,KlPV @0aB$#$cij*NFIiA[#P'Hmk'D%mJh*T,r&0T!Sj!!I%QRN!"4J!C25i'JdhRAG4# +iPZ,'C)pS[%JqMbf%5Z@HYTRpTjm`P9K-jj6!9j,5+E8[jbd,$Qb,rLerVlm'a" EJ,NAIG%b0S`!KTfSi1,Hlm6&Tl86i@XA-SjmDCVVm2JR[U[ZUaabTc`"ZLc''*T MA06`8"HaVhrb,12m0TYp8$49BH,J(bC-qMij8S3`iIJLm!&DUAX,NDT4j(cCZq` Sjr#YLPbe+8AqUc@cBNPJ0I"'D`jmfZPUpmQhXQ'2G"i,XrX6PZh5*UdATE`QBJT 2*-NNJ'H03hDLq3NLl8V#BcH(SN53!&)l)I#5DJXfUc)pbK*kKMMdhlkIbRYcdU* -kaTcDabVQGjqY*`D1++%&&hPjA0$mc46dA5Pa&+%QbaXIY(9*40iKhGhE(!d(Zj TU%6JfY"(KHR"&-pfT-D8AB"c'iDKcqH'9"0#TcflZJ5YE#(YDU4QTYFS*`lY2+' HUH+"N6hThTfY$V%@bmP3RrZVqj*lIM!qQ&'(*R8#YUX0ViVa-8c1cLi5mSh423Y c"ZTZ&UCCXZeRVUh#+(cU-p`4R%4,2aCl@ZeXXYH'f1j5r6'Fdp6k&d9CITqHK#@ jRIp9LG#d$jCXIJ9ZTRb1X1r#JCA&JjmSEMUfVbL!D[6I$5#JScE6Na9lmKfF0EH V"15k'@bDdk%miP"ThZ@A0I0@V`65l5S9deFHd#$hUXR5GDT"DMik$YJL+GmY#CB f%KC+a"&%)ihiBfR+0I#@&ENYGGfGh1ZaX"RlLlZ$l-9X9H*LaaQqEZ6LZ'rpIM* GCa`prJ+&V"j-rb!(B[h8XVQbRfQhYc,GJ(J65aIbPCVha(mX8UAS2e@%VYZYMF( $UMM#pf[eK66(Dj1)d*GNK+[I"ZK52ijfp01Pj098q,AA1GUbRR,5Z)jBdJMD1LZ Y8$2iKCVB!R2!PiF*N!$Ycb2#1Nh6&f-fSDEc2YH1jp9GM@!XI'*ilG-Qc4qT0fe dIZdlC9qP)X!!&@4T9A$EaNq-AZKQ6%R$$a54DScX[R*,M*!!k)K4LrB9Ma0[+II jcUfa44M*R18DLAMSp36ELf),#2#qPidNRI[QVFj%D95q)Xa`RS6EjCd+5BN6MeV %!,Q1a$r!B1`Bp3FM8IpLD)S+$G#+BR1)d#!hB9'5GRjMXFLAC-06*FkSLrBpG6X ,q$JVU-a-"TBp@F)+T`$8S[Dj!EIek6Ei!CIBUAGZpERj!eKb9(,X'RqjiBH5bbP -M*hrM9L`Xhl"GqM#U-f9*jXA"IQeZ[b#&`DqGehATT!!(S$6dqLGCl@A-NeefUB CPHNb!6cQp-!L[%Qal$RBVE9ZN!#qrF#!'d&V@ceTH8bbU3`DV0!06TamU$%('FZ l0N`a41a+-&6)Jcjl2XS1jHBp[HE"-PTaj6*#rZXdIX8%X8XRqJXc(FN5iG%bELS +b,60YmQf"J65!j!!D%+B#Ik0&-B3B@*GM[jJlJBU$RkG93B`&-#!h+HerJ8PT,@ b4!M[IeX(5fA%bFZLUp@K6(mkd@BTHhBcDkGaJh0`$CA2N!#3!%G1-Ne!SYh%drH F,BQM`')#DqM&#U(*Y-1lG45[6@GDN!#,bMKZRMG8"D$T2Kc192P!mSK@0AC8#3E D5,p-B+X2ZcmCQAIc,2AEdK5!+1N5*`cl9qJ@N!")h+G,fYaRJrRN`dd1NQ"E$VL ki6&AIilJU6[Z6pR5B*U9Rm1S[dr`a6mp3Fd`ArhVJQ!TR9T#ZhI+MpjYcFC*Tpf JP)[hkrKT5D`IVBCl"QA0TS2!TdYN8%E#epb&4PA9Q-hQ50A5SA@GjUa`kE-X-HM +d28*r*JYMjd!ICRc,(ZrmcU5e(4KNd[IAR$U[Tm*rdK"&(P&HE,U5c&(#0[`'-D 5f6@Qdr3dIB[VAlQbBHEiXrVYae)ZjkP@,'U[dE)NKfe95B9"Jk0'I$A8b$VC&CI hj0TB-$9m0"N8$CIaHe"M2@3-GQ$(12rHGfTrFM[EP9BMH3B`fcFE2PM'VNZ+fSm R[kIC&VabE@DX[9ZChF-R3*X*[Gmakl`@[!XBM"Iq3#d4e2`)6dE"fe2&5r'*3)D fB!kY""qf-#Xh!5DUNqDYG(&`URfpc*RAAS-#r+D@!A[j8r[eAi!S-rimJJ'!JGb %*BZ5$!f,GjJjLa5D")q,RL4XR[Ppi(r8RNiP$2e@ALL+bU&lUIljbU5MXf56RSK #8KbRX8C@f&kmYX-V,K+TmASNfml4&HPfSV$Y(&Y&J8ER)M[,N!"VmB&c'$a2h'h c`MAp!+rpRY(4Qe8@Z#el[0+YYH#ZYd3EMkbHRechUKDqX5k8m)cfAKj'mJ*[h6' 6)pLEDAqcBBi5[CE[rpIkcC%LIUe3f4@8TFUBfZ9B6FYY-F)N[fBV'h3@(m&iB,a )d1HkSQUS"C91!eHTUrHa9J[FLDk'K8-H9XmKc$L*'V5H'-5[*p)TC'El!$b2J"k T0Ul!A)(4ZlVY!Te#X5V)+@[J"r1e-BdkRFe`N!#r0DcM"VUBekGkJe,*5cpX0PS T(d3588LNcfA!1-TB8GQ`K0eIIl0N96)Nd!Rb%&4LIRETS'P3+jA+Bi9SY#qCmGI 5Ai,[V-NK#La5439PX&LDc8hTl$aLj359-bqmDJZ)GiaX1k1[k)bMZ2r(U*c[Gej %D)m*@@+eGqbF249V)fRpkp)6e0JrHiB*[K8*9fGR-AU+jTcpi#f0+U0+L@Yc'U2 dc04kb961J1JdC5PLEV30PJSYZXJ#jfdlb$,0UrY"jX[RkUY8JLY)-L`Gj6ieH'6 %C*LCT`)3ZS@[X2!%!-SJKp1jEL2Cml64,qZhPa)'AidDL1Ybp@6`iI80l+RfHpd Y1XF"[0[r!$B*PqDdHB95)l8[1I%*Nr,#e&Y3CCiNFC[8dj9TDKdh)Q6,,fCk(S# pQbBT0TY@PD(I@lDhBV%Pk9GrD%IY,YpIM-V9cE(UBbG2&Xck6c5I1BcMA-YcJFA 0,Q"*[F1C16*jHTMMPV0@6HYDU5V0`dPbD&X+MPSlR&+hbi36I8(5pBhrN!$Nj*a Z#!akZ&EGD+M,95XdGQGpfB`RY9BjCa9"Jp0EhH,EFY$Xp0#fq5DI#KVJBj,10hZ `Bq#LBCm2%H@E,+X9!b92Xb3iDFh4MVPIpfIVl"rkr%Eie%$X)MHS6PM!XTB'1$H kR%(U%"b&pq)aqe3a9TkCmFDMGk2qq%"HEh*XqVLk9-A,*pAd(dpZSG2Q#&qCJP2 X5cRMX'hX$'L5*+0!i`51"Yaj''JmqAJA#qUqe!P,MR-!NDje18N(qV3@5C1&B`D IqHRl9X2i2T6ZJH'e!jK,MY#3!+TSYiGI*AaPcjIbGE,pQ5[0Bk@%Ahrf#aQ$NkU d!GNU@XiVQ!T6'EHGZC4@(Qf-icF'*X1,1elXp1L)jmi`Y"F,'Fll%A@'$Mp1IT% 4pZjYGj%b,8rhMFlIh1-NN!#MD$'mrpeRD+18mX9YJ+9kiQE-B&U''*jE1*6raUl $40TV"8Aj2`cF3YHakZ6%05+TZ8&#e4HlCpJjL2$)l&2RNVNKBEAbL2UqijV4C,4 !9bq*`lQDp-&$iV8-!)S2)(el3Gp5lfekXY%TkcB%-PkqfD`DRD,R`APCTf%SkYi YkMk9pc01i''-FlHj6bF6QU%PJ+-@4DbAp91&Q,4`0mc1'1(,P6j)j1fMGbAf%BG ,M8&e!2R'Uk,%Rcm9JkL53'"eTe@IXaCCY!0!33RNL)DY5CYmjN%VhK,U8GXFG+[ 8jmX*Z2'(9BE)F'c"[r"4(UF4E*Qa[Nk-j&"MM!B6UZ*0YpL'!+9)G*&k,&2l@&& AbpQL&q)IrbB+ED(J8lRM"*Ii6%VUADiNE'dVU'q%[LHeia*6Y%89acHSZLZH(mq I[jRmr6$mVc-RTPb8+)ZMjI@hNG(F0VT&bU@(Hq1!F"2j881[Z$Nm5SC@1$41qHC Z*B%dX0kZFfcHDPjCH`GJrbU5DkEdIaTUI+NaK"PdSmI[LPTLJ9IJ8KA#kV"2Uia KdERdQFN93d"lqUqXj@Mr+*qi6&"UECZ-#,*iEC&C`bZqlMfYpM(epQ)*%&C![LJ hPR8L[G0#*-Pj,5P*C$cF+BTi2&i!bX+hlrFri`8+M'SNkXcMM(Q3!%%A2MlD*28 VCqT[JjMIq0PTUq0qPSAf4a0$XLC)-48j(c*)V1K5Pc(m%SGL+($j+p8S%dQ3!&Z lQ%+#S[eP8p$5$[$Vq)R)6HaCkZT5CT&*Rb,2I'PA"EVrJTPJKBE@Xi$J%rQAiUE $fqc2ald8l1R&r%FZ(Gq*VR(@l'M!MiUBId*-Kd&S!pP"YBNkYP[B[Z%YlT5SmY! 2rJF43CSX-e@Gp1FDa-d'!JQ@al9raL0r$[fkG0#D5VmHClHGEqhD`fmVA[jC+rM (&qL@f"N"(1DT-#2bD)j)N3!`Tr&$Rep"LN@aR!Rl(5lcE1UYTUmcVKrX(f1)40K Y4RQl"CKXF9C08YC(*$aR5a@QalMZGITR05QRZ"+h`52GmMN4pj6iXh*6MZFb8ke arcTIYkJ%@!F4TNFBfCKU#I3SZViZSKC0e*!!"cFIrhEC%XbSMX6jaS5&9#h@!`d [Y&`V)j*NiURXkhF0DP5e2dAG*Z,9N!$*D[l1$KF5SNi[b"J@Z2Di),1E93CDGmd Gb1)8,k@iE`R'kNHkLYb%dGd34Y,C013(''CiPAT2BRL[dYPHEY6ZE'`i0f-mp)a X&[HT"f3K+8rfE`T!,%MI)YZKJqZ#ZDTfGRYe'+5[Ke+2E%ecBS3pPC!!rU*,drD &884$ZmbC%Y-Iea(IUfjblN-*cX2hB`Mr+aG#AhMaaJfKPbd5P[+H$9A'(jGqcQ- 2pAc0'J[b`hF4+N1dYV[8#-aHm&FiqHbK`R8PpZ*be,`-[a"P"q1lcb$Z8I%0RA2 X8bcClk*cpGU1Q5c6VI%#`63X"PYE,*Hi3bF21r2JTij#%Q3J'cij@e+-99)rZqB $DdVZbrG[S8$eBj!!@$Z3!%C,DD1H[Dr+iFXKGGD&**8$2mqBZG+M+&`P%``#e8Y 13020cm&rj9ND(4q*S+D%eYGi'X(IT1lA+fV1,T!!6(fcKe2S6"!X-C-F-TqlSTB BJTb$,U'!bY8!!!: \ No newline at end of file
diff --git a/src/macos/src/curl_GUSIConfig.cpp b/src/macos/src/curl_GUSIConfig.cpp
new file mode 100644
index 000000000..fc9378ae2
--- /dev/null
+++ b/src/macos/src/curl_GUSIConfig.cpp
@@ -0,0 +1 @@
+/**************** BEGIN GUSI CONFIGURATION **************************** * * GUSI Configuration section generated by GUSI Configurator * last modified: Mon Oct 29 15:41:51 2001 * * This section will be overwritten by the next run of Configurator. */ #define GUSI_SOURCE #include <GUSIConfig.h> #include <sys/cdefs.h> /* Declarations of Socket Factories */ __BEGIN_DECLS void GUSIwithInetSockets(); void GUSIwithLocalSockets(); void GUSIwithMTInetSockets(); void GUSIwithMTTcpSockets(); void GUSIwithMTUdpSockets(); void GUSIwithOTInetSockets(); void GUSIwithOTTcpSockets(); void GUSIwithOTUdpSockets(); void GUSIwithPPCSockets(); void GUSISetupFactories(); __END_DECLS /* Configure Socket Factories */ void GUSISetupFactories() { #ifdef GUSISetupFactories_BeginHook GUSISetupFactories_BeginHook #endif GUSIwithInetSockets(); #ifdef GUSISetupFactories_EndHook GUSISetupFactories_EndHook #endif } /* Declarations of File Devices */ __BEGIN_DECLS void GUSIwithNullSockets(); void GUSISetupDevices(); __END_DECLS /* Configure File Devices */ void GUSISetupDevices() { #ifdef GUSISetupDevices_BeginHook GUSISetupDevices_BeginHook #endif GUSIwithNullSockets(); #ifdef GUSISetupDevices_EndHook GUSISetupDevices_EndHook #endif } #ifndef __cplusplus #error GUSISetupConfig() needs to be written in C++ #endif GUSIConfiguration::FileSuffix sSuffices[] = { "", '????', '????' }; extern "C" void GUSISetupConfig() { GUSIConfiguration * config = GUSIConfiguration::CreateInstance(GUSIConfiguration::kNoResource); config->ConfigureDefaultTypeCreator('TEXT', 'CWIE'); config->ConfigureSuffices( sizeof(sSuffices)/sizeof(GUSIConfiguration::FileSuffix)-1, sSuffices); } /**************** END GUSI CONFIGURATION *************************/ \ No newline at end of file
diff --git a/src/macos/src/macos_main.cpp b/src/macos/src/macos_main.cpp
new file mode 100644
index 000000000..cf3075ffc
--- /dev/null
+++ b/src/macos/src/macos_main.cpp
@@ -0,0 +1 @@
+/* ========================================================================= Copyright (C) 2001 Eric Lavigne Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: - The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from defects in it. - The origin of this software must not be misrepresented, either by explicit claim or by omission. - You are allowed to distributed modified copies of the software, in source and binary form, provided they are marked plainly as altered versions, and are not misrepresented as being the original software. ========================================================================= */ #include <stdlib.h> #include <string.h> #include <stdio.h> #include <Memory.h> #include <GUSICommandLine.h> #include <stdlib.h> /* ========================================================================= */ DECLARE_MAIN(curl) REGISTER_MAIN_START REGISTER_MAIN(curl) REGISTER_MAIN_END /* ========================================================================= */ int main() { ::MaxApplZone(); for (int i = 1; i <= 10; i++) ::MoreMasters(); (void) exec_commands(); return 0; } \ No newline at end of file
diff --git a/src/makefile.amiga b/src/makefile.amiga
new file mode 100644
index 000000000..dc984811a
--- /dev/null
+++ b/src/makefile.amiga
@@ -0,0 +1,32 @@
+#
+# $VER: cURL Makefile for AmigaOS ...
+#
+
+# change the follow to where you have the AmiTCP SDK v4.3 includes:
+
+ATCPSDKI= /GG/netinclude
+
+
+CC = m68k-amigaos-gcc
+CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall
+LIBS = ../lib/libcurl.a -lssl -lcrypto -lz
+MANPAGE = ../docs/curl.1
+README = ../docs/MANUAL
+MKHELP = ../src/mkhelp.pl
+
+top_srcdir = ..
+
+include Makefile.inc
+
+OBJS = $(CURL_CFILES:.c=.o) $(CURLX_ONES:.c=.o)
+
+all: hugehelp.c $(OBJS)
+ $(CC) $(CFLAGS) -o cURL $(OBJS) $(LIBS) -Wl,-Map,cURL.map,--cref
+
+hugehelp.c: $(README) $(MANPAGE) mkhelp.pl
+ rm -f hugehelp.c
+ /bin/nroff -man $(MANPAGE) | /bin/perl $(MKHELP) -c $(README) > hugehelp.c
+
+install:
+ $(INSTALL) -c cURL /c/cURL
+
diff --git a/src/makefile.dj b/src/makefile.dj
new file mode 100644
index 000000000..094ef665a
--- /dev/null
+++ b/src/makefile.dj
@@ -0,0 +1,75 @@
+#
+# Adapted for djgpp2 / Watt-32 / DOS by
+# Gisle Vanem <gvanem@broadpark.no>
+#
+
+DEPEND_PREREQ = # hugehelp.c
+
+top_srcdir = ..
+TOPDIR = ..
+
+include ../packages/DOS/common.dj
+include Makefile.inc
+
+CSOURCES = $(CURL_CFILES)
+
+ifeq ($(USE_SSL),1)
+ EX_LIBS += $(OPENSSL_ROOT)/lib/libssl.a $(OPENSSL_ROOT)/lib/libcrypt.a
+endif
+
+ifeq ($(USE_ARES),1)
+ EX_LIBS += $(ARES_ROOT)/libcares.a
+endif
+
+ifeq ($(USE_ZLIB),1)
+ EX_LIBS += $(ZLIB_ROOT)/libz.a
+ CFLAGS += -DUSE_MANUAL
+endif
+
+ifeq ($(USE_IDNA),1)
+ EX_LIBS += $(LIBIDN_ROOT)/lib/dj_obj/libidn.a -liconv
+endif
+
+EX_LIBS += $(WATT32_ROOT)/lib/libwatt.a
+
+CFLAGS += -DUSE_ENVIRONMENT
+
+PROGRAM = curl.exe
+OBJECTS += $(addprefix $(OBJ_DIR)/, $(CSOURCES:.c=.o))
+
+all: $(OBJ_DIR) $(PROGRAM)
+ @echo Welcome to cURL
+
+$(PROGRAM): $(OBJECTS) ../lib/libcurl.a
+ $(CC) -o $@ $^ $(LDFLAGS) $(EX_LIBS)
+
+#
+# groff 1.18+ requires "-P -c"
+#
+hugehelp.c: ../docs/MANUAL ../docs/curl.1 mkhelp.pl
+ groff -Tascii -man ../docs/curl.1 | \
+ perl -w mkhelp.pl ../docs/MANUAL > $@
+
+# clean generated files
+#
+genclean:
+ - $(DELETE) hugehelp.c
+
+# clean object files and subdir
+#
+objclean: genclean
+ - $(DELETE) $(OBJ_DIR)$(DS)*.o
+ - $(RMDIR) $(OBJ_DIR)
+
+# clean without removing built program
+#
+clean: objclean
+ - $(DELETE) depend.dj
+
+# clean everything
+#
+realclean vclean: clean
+ - $(DELETE) $(PROGRAM)
+
+-include depend.dj
+
diff --git a/src/mkhelp.pl b/src/mkhelp.pl
new file mode 100644
index 000000000..ff4604155
--- /dev/null
+++ b/src/mkhelp.pl
@@ -0,0 +1,262 @@
+#!/usr/local/bin/perl
+#***************************************************************************
+# _ _ ____ _
+# Project ___| | | | _ \| |
+# / __| | | | |_) | |
+# | (__| |_| | _ <| |___
+# \___|\___/|_| \_\_____|
+#
+# Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://curl.haxx.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+###########################################################################
+
+# Yeah, I know, probably 1000 other persons already wrote a script like
+# this, but I'll tell ya:
+
+# THEY DON'T FIT ME :-)
+
+# Get readme file as parameter:
+
+if($ARGV[0] eq "-c") {
+ $c=1;
+ shift @ARGV;
+}
+
+my $README = $ARGV[0];
+
+if($README eq "") {
+ print "usage: mkreadme.pl [-c] <README> < manpage\n";
+ exit;
+}
+
+
+push @out, " _ _ ____ _\n";
+push @out, " Project ___| | | | _ \\| |\n";
+push @out, " / __| | | | |_) | |\n";
+push @out, " | (__| |_| | _ <| |___\n";
+push @out, " \\___|\\___/|_| \\_\\_____|\n";
+
+my $olen=0;
+while (<STDIN>) {
+ my $line = $_;
+
+ # this should be removed:
+ $line =~ s/(.|_)//g;
+
+ if($line =~ /^([ \t]*\n|curl)/i) {
+ # cut off headers and empty lines
+ $wline++; # count number of cut off lines
+ next;
+ }
+
+ my $text = $line;
+ $text =~ s/^\s+//g; # cut off preceding...
+ $text =~ s/\s+$//g; # and trailing whitespaces
+
+ $tlen = length($text);
+
+ if($wline && ($olen == $tlen)) {
+ # if the previous line with contents was exactly as long as
+ # this line, then we ignore the newlines!
+
+ # We do this magic because a header may abort a paragraph at
+ # any line, but we don't want that to be noticed in the output
+ # here
+ $wline=0;
+ }
+ $olen = $tlen;
+
+ if($wline) {
+ # we only make one empty line max
+ $wline = 0;
+ push @out, "\n";
+ }
+ push @out, $line;
+}
+push @out, "\n"; # just an extra newline
+
+open(READ, "<$README") ||
+ die "couldn't read the README infile $README";
+
+while(<READ>) {
+ push @out, $_;
+}
+close(READ);
+
+# if compressed
+if($c) {
+ my @test = `gzip --version 2>&1`;
+ if($test[0] =~ /gzip/) {
+ open(GZIP, ">dumpit") ||
+ die "can't create the dumpit file, try without -c";
+ binmode GZIP;
+ for(@out) {
+ print GZIP $_;
+ $gzip += length($_);
+ }
+ close(GZIP);
+
+ system("gzip --best --no-name dumpit");
+
+ open(GZIP, "<dumpit.gz") ||
+ die "can't read the dumpit.gz file, try without -c";
+ binmode GZIP;
+ while(<GZIP>) {
+ push @gzip, $_;
+ $gzipped += length($_);
+ }
+ close(GZIP);
+
+ unlink("dumpit.gz");
+ }
+ else {
+ # no gzip, no compression!
+ undef $c;
+ print STDERR "MEEEP: Couldn't find gzip, disable compression\n";
+ }
+}
+
+$now = localtime;
+print <<HEAD
+/*
+ * NEVER EVER edit this manually, fix the mkhelp.pl script instead!
+ * Generation time: $now
+ */
+#ifdef USE_MANUAL
+#include "hugehelp.h"
+HEAD
+ ;
+if($c) {
+ print <<HEAD
+#include <zlib.h>
+#include "memdebug.h" /* keep this as LAST include */
+static const unsigned char hugehelpgz[] = {
+ /* This mumbo-jumbo is the huge help text compressed with gzip.
+ Thanks to this operation, the size of this data shrunk from $gzip
+ to $gzipped bytes. You can disable the use of compressed help
+ texts by NOT passing -c to the mkhelp.pl tool. */
+HEAD
+;
+ my $c=0;
+ print " ";
+ for(@gzip) {
+ my @all=split(//, $_);
+ for(@all) {
+ my $num=ord($_);
+ printf(" 0x%02x,", 0+$num);
+ if(++$c>11) {
+ print "\n ";
+ $c=0;
+ }
+ }
+ }
+ print "\n};\n";
+
+ print <<EOF
+#define BUF_SIZE 0x10000
+static voidpf zalloc_func(voidpf opaque, unsigned int items, unsigned int size)
+{
+ (void) opaque;
+ /* not a typo, keep it calloc() */
+ return (voidpf) calloc(items, size);
+}
+static void zfree_func(voidpf opaque, voidpf ptr)
+{
+ (void) opaque;
+ free(ptr);
+}
+/* Decompress and send to stdout a gzip-compressed buffer */
+void hugehelp(void)
+{
+ unsigned char* buf;
+ int status,headerlen;
+ z_stream z;
+
+ /* Make sure no gzip options are set */
+ if (hugehelpgz[3] & 0xfe)
+ return;
+
+ headerlen = 10;
+ memset(&z, 0, sizeof(z_stream));
+ z.zalloc = (alloc_func)zalloc_func;
+ z.zfree = (free_func)zfree_func;
+ z.avail_in = (unsigned int)(sizeof(hugehelpgz) - headerlen);
+ z.next_in = (unsigned char *)hugehelpgz + headerlen;
+
+ if (inflateInit2(&z, -MAX_WBITS) != Z_OK)
+ return;
+
+ buf = malloc(BUF_SIZE);
+ if (buf) {
+ while(1) {
+ z.avail_out = BUF_SIZE;
+ z.next_out = buf;
+ status = inflate(&z, Z_SYNC_FLUSH);
+ if (status == Z_OK || status == Z_STREAM_END) {
+ fwrite(buf, BUF_SIZE - z.avail_out, 1, stdout);
+ if (status == Z_STREAM_END)
+ break;
+ }
+ else
+ break; /* Error */
+ }
+ free(buf);
+ }
+ inflateEnd(&z);
+}
+EOF
+ ;
+foot();
+exit;
+}
+else {
+ print <<HEAD
+void hugehelp(void)
+{
+ fputs(
+HEAD
+ ;
+}
+
+$outsize=0;
+for(@out) {
+ chop;
+
+ $new = $_;
+
+ $outsize += length($new)+1; # one for the newline
+
+ $new =~ s/\\/\\\\/g;
+ $new =~ s/\"/\\\"/g;
+
+ # gcc 2.96 claims ISO C89 only is required to support 509 letter strings
+ if($outsize > 500) {
+ # terminate and make another fputs() call here
+ print ", stdout);\n fputs(\n";
+ $outsize=length($new)+1;
+ }
+ printf("\"%s\\n\"\n", $new);
+
+}
+
+print ", stdout) ;\n}\n";
+
+foot();
+
+sub foot {
+ print <<FOOT
+#endif /* USE_MANUAL */
+FOOT
+ ;
+}
diff --git a/src/tool_binmode.c b/src/tool_binmode.c
new file mode 100644
index 000000000..92033ac03
--- /dev/null
+++ b/src/tool_binmode.c
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef HAVE_SETMODE
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#include "tool_binmode.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+void set_binmode(FILE *stream)
+{
+#ifdef O_BINARY
+# ifdef __HIGHC__
+ _setmode(stream, O_BINARY);
+# else
+ setmode(fileno(stream), O_BINARY);
+# endif
+#else
+ (void)stream;
+#endif
+}
+
+#endif /* HAVE_SETMODE */
+
diff --git a/src/tool_binmode.h b/src/tool_binmode.h
new file mode 100644
index 000000000..b5cb08d55
--- /dev/null
+++ b/src/tool_binmode.h
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_TOOL_BINMODE_H
+#define HEADER_CURL_TOOL_BINMODE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef HAVE_SETMODE
+
+void set_binmode(FILE *stream);
+
+#else
+
+#define set_binmode(x) Curl_nop_stmt
+
+#endif /* HAVE_SETMODE */
+
+#endif /* HEADER_CURL_TOOL_BINMODE_H */
+
diff --git a/src/tool_bname.c b/src/tool_bname.c
new file mode 100644
index 000000000..277830546
--- /dev/null
+++ b/src/tool_bname.c
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "tool_bname.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifndef HAVE_BASENAME
+
+char *tool_basename(char *path)
+{
+ char *s1;
+ char *s2;
+
+ s1 = strrchr(path, '/');
+ s2 = strrchr(path, '\\');
+
+ if(s1 && s2) {
+ path = (s1 > s2) ? s1 + 1 : s2 + 1;
+ }
+ else if(s1)
+ path = s1 + 1;
+ else if(s2)
+ path = s2 + 1;
+
+ return path;
+}
+
+#endif /* HAVE_BASENAME */
+
diff --git a/src/tool_bname.h b/src/tool_bname.h
new file mode 100644
index 000000000..69cf92c1b
--- /dev/null
+++ b/src/tool_bname.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_TOOL_BNAME_H
+#define HEADER_CURL_TOOL_BNAME_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifndef HAVE_BASENAME
+
+char *tool_basename(char *path);
+
+#define basename(x) tool_basename((x))
+
+#endif /* HAVE_BASENAME */
+
+#endif /* HEADER_CURL_TOOL_BNAME_H */
+
diff --git a/src/tool_cb_dbg.c b/src/tool_cb_dbg.c
new file mode 100644
index 000000000..1850ba0c6
--- /dev/null
+++ b/src/tool_cb_dbg.c
@@ -0,0 +1,275 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+#include "tool_cb_dbg.h"
+#include "tool_util.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+static void dump(const char *timebuf, const char *text,
+ FILE *stream, const unsigned char *ptr, size_t size,
+ trace tracetype, curl_infotype infotype);
+
+/*
+** callback for CURLOPT_DEBUGFUNCTION
+*/
+
+int tool_debug_cb(CURL *handle, curl_infotype type,
+ unsigned char *data, size_t size,
+ void *userdata)
+{
+ struct Configurable *config = userdata;
+ FILE *output = config->errors;
+ const char *text;
+ struct timeval tv;
+ struct tm *now;
+ char timebuf[20];
+ time_t secs;
+ static time_t epoch_offset;
+ static int known_offset;
+
+ (void)handle; /* not used */
+
+ if(config->tracetime) {
+ tv = tvnow();
+ if(!known_offset) {
+ epoch_offset = time(NULL) - tv.tv_sec;
+ known_offset = 1;
+ }
+ secs = epoch_offset + tv.tv_sec;
+ now = localtime(&secs); /* not thread safe but we don't care */
+ snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
+ now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
+ }
+ else
+ timebuf[0] = 0;
+
+ if(!config->trace_stream) {
+ /* open for append */
+ if(curlx_strequal("-", config->trace_dump))
+ config->trace_stream = stdout;
+ else if(curlx_strequal("%", config->trace_dump))
+ /* Ok, this is somewhat hackish but we do it undocumented for now */
+ config->trace_stream = config->errors; /* aka stderr */
+ else {
+ config->trace_stream = fopen(config->trace_dump, "w");
+ config->trace_fopened = TRUE;
+ }
+ }
+
+ if(config->trace_stream)
+ output = config->trace_stream;
+
+ if(!output) {
+ warnf(config, "Failed to create/open output");
+ return 0;
+ }
+
+ if(config->tracetype == TRACE_PLAIN) {
+ /*
+ * This is the trace look that is similar to what libcurl makes on its
+ * own.
+ */
+ static const char * const s_infotype[] = {
+ "*", "<", ">", "{", "}", "{", "}"
+ };
+ size_t i;
+ size_t st = 0;
+ static bool newl = FALSE;
+ static bool traced_data = FALSE;
+
+ switch(type) {
+ case CURLINFO_HEADER_OUT:
+ if(size > 0) {
+ for(i = 0; i < size - 1; i++) {
+ if(data[i] == '\n') { /* LF */
+ if(!newl) {
+ fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+ }
+ (void)fwrite(data + st, i - st + 1, 1, output);
+ st = i + 1;
+ newl = FALSE;
+ }
+ }
+ if(!newl)
+ fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+ (void)fwrite(data + st, i - st + 1, 1, output);
+ }
+ newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
+ traced_data = FALSE;
+ break;
+ case CURLINFO_TEXT:
+ case CURLINFO_HEADER_IN:
+ if(!newl)
+ fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+ (void)fwrite(data, size, 1, output);
+ newl = (size && (data[size - 1] != '\n')) ? TRUE : FALSE;
+ traced_data = FALSE;
+ break;
+ case CURLINFO_DATA_OUT:
+ case CURLINFO_DATA_IN:
+ case CURLINFO_SSL_DATA_IN:
+ case CURLINFO_SSL_DATA_OUT:
+ if(!traced_data) {
+ /* if the data is output to a tty and we're sending this debug trace
+ to stderr or stdout, we don't display the alert about the data not
+ being shown as the data _is_ shown then just not via this
+ function */
+ if(!config->isatty ||
+ ((output != stderr) && (output != stdout))) {
+ if(!newl)
+ fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+ fprintf(output, "[data not shown]\n");
+ newl = FALSE;
+ traced_data = TRUE;
+ }
+ }
+ break;
+ default: /* nada */
+ newl = FALSE;
+ traced_data = FALSE;
+ break;
+ }
+
+ return 0;
+ }
+
+#ifdef CURL_DOES_CONVERSIONS
+ /* Special processing is needed for CURLINFO_HEADER_OUT blocks
+ * if they contain both headers and data (separated by CRLFCRLF).
+ * We dump the header text and then switch type to CURLINFO_DATA_OUT.
+ */
+ if((type == CURLINFO_HEADER_OUT) && (size > 4)) {
+ size_t i;
+ for(i = 0; i < size - 4; i++) {
+ if(memcmp(&data[i], "\r\n\r\n", 4) == 0) {
+ /* dump everything through the CRLFCRLF as a sent header */
+ text = "=> Send header";
+ dump(timebuf, text, output, data, i + 4, config->tracetype, type);
+ data += i + 3;
+ size -= i + 4;
+ type = CURLINFO_DATA_OUT;
+ data += 1;
+ break;
+ }
+ }
+ }
+#endif /* CURL_DOES_CONVERSIONS */
+
+ switch (type) {
+ case CURLINFO_TEXT:
+ fprintf(output, "%s== Info: %s", timebuf, data);
+ default: /* in case a new one is introduced to shock us */
+ return 0;
+
+ case CURLINFO_HEADER_OUT:
+ text = "=> Send header";
+ break;
+ case CURLINFO_DATA_OUT:
+ text = "=> Send data";
+ break;
+ case CURLINFO_HEADER_IN:
+ text = "<= Recv header";
+ break;
+ case CURLINFO_DATA_IN:
+ text = "<= Recv data";
+ break;
+ case CURLINFO_SSL_DATA_IN:
+ text = "<= Recv SSL data";
+ break;
+ case CURLINFO_SSL_DATA_OUT:
+ text = "=> Send SSL data";
+ break;
+ }
+
+ dump(timebuf, text, output, data, size, config->tracetype, type);
+ return 0;
+}
+
+static void dump(const char *timebuf, const char *text,
+ FILE *stream, const unsigned char *ptr, size_t size,
+ trace tracetype, curl_infotype infotype)
+{
+ size_t i;
+ size_t c;
+
+ unsigned int width = 0x10;
+
+ if(tracetype == TRACE_ASCII)
+ /* without the hex output, we can fit more on screen */
+ width = 0x40;
+
+ fprintf(stream, "%s%s, %zd bytes (0x%zx)\n", timebuf, text, size, size);
+
+ for(i = 0; i < size; i += width) {
+
+ fprintf(stream, "%04zx: ", i);
+
+ if(tracetype == TRACE_BIN) {
+ /* hex not disabled, show it */
+ for(c = 0; c < width; c++)
+ if(i+c < size)
+ fprintf(stream, "%02x ", ptr[i+c]);
+ else
+ fputs(" ", stream);
+ }
+
+ for(c = 0; (c < width) && (i+c < size); c++) {
+ /* check for 0D0A; if found, skip past and start a new line of output */
+ if((tracetype == TRACE_ASCII) &&
+ (i+c+1 < size) && (ptr[i+c] == 0x0D) && (ptr[i+c+1] == 0x0A)) {
+ i += (c+2-width);
+ break;
+ }
+#ifdef CURL_DOES_CONVERSIONS
+ /* repeat the 0D0A check above but use the host encoding for CRLF */
+ if((tracetype == TRACE_ASCII) &&
+ (i+c+1 < size) && (ptr[i+c] == '\r') && (ptr[i+c+1] == '\n')) {
+ i += (c+2-width);
+ break;
+ }
+ /* convert to host encoding and print this character */
+ fprintf(stream, "%c", convert_char(infotype, ptr[i+c]));
+#else
+ (void)infotype;
+ fprintf(stream, "%c", ((ptr[i+c] >= 0x20) && (ptr[i+c] < 0x80)) ?
+ ptr[i+c] : UNPRINTABLE_CHAR);
+#endif /* CURL_DOES_CONVERSIONS */
+ /* check again for 0D0A, to avoid an extra \n if it's at width */
+ if((tracetype == TRACE_ASCII) &&
+ (i+c+2 < size) && (ptr[i+c+1] == 0x0D) && (ptr[i+c+2] == 0x0A)) {
+ i += (c+3-width);
+ break;
+ }
+ }
+ fputc('\n', stream); /* newline */
+ }
+ fflush(stream);
+}
+
diff --git a/src/tool_cb_dbg.h b/src/tool_cb_dbg.h
new file mode 100644
index 000000000..d0ed7b0d4
--- /dev/null
+++ b/src/tool_cb_dbg.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_TOOL_CB_DBG_H
+#define HEADER_CURL_TOOL_CB_DBG_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+/*
+** callback for CURLOPT_DEBUGFUNCTION
+*/
+
+int tool_debug_cb(CURL *handle, curl_infotype type,
+ unsigned char *data, size_t size,
+ void *userdata);
+
+#endif /* HEADER_CURL_TOOL_CB_DBG_H */
+
diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c
new file mode 100644
index 000000000..ef340f798
--- /dev/null
+++ b/src/tool_cb_hdr.c
@@ -0,0 +1,225 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+#include "tool_cb_hdr.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+static char *parse_filename(const char *ptr, size_t len);
+
+/*
+** callback for CURLOPT_HEADERFUNCTION
+*/
+
+size_t tool_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
+{
+ struct HdrCbData *hdrcbdata = userdata;
+ struct OutStruct *outs = hdrcbdata->outs;
+ struct OutStruct *heads = hdrcbdata->heads;
+ const char *str = ptr;
+ const size_t cb = size * nmemb;
+ const char *end = (char*)ptr + cb;
+
+ /*
+ * Once that libcurl has called back tool_header_cb() the returned value
+ * is checked against the amount that was intended to be written, if
+ * it does not match then it fails with CURLE_WRITE_ERROR. So at this
+ * point returning a value different from sz*nmemb indicates failure.
+ */
+ size_t failure = (size * nmemb) ? 0 : 1;
+
+ if(!heads->config)
+ return failure;
+
+#ifdef DEBUGBUILD
+ if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) {
+ warnf(heads->config, "Header data exceeds single call write limit!\n");
+ return failure;
+ }
+#endif
+
+ /*
+ * Write header data when curl option --dump-header (-D) is given.
+ */
+
+ if(heads->config->headerfile && heads->stream) {
+ size_t rc = fwrite(ptr, size, nmemb, heads->stream);
+ if(rc != cb)
+ return rc;
+ }
+
+ /*
+ * This callback sets the filename where output shall be written when
+ * curl options --remote-name (-O) and --remote-header-name (-J) have
+ * been simultaneously given and additionally server returns an HTTP
+ * Content-Disposition header specifying a filename property.
+ */
+
+ if(hdrcbdata->honor_cd_filename &&
+ (cb > 20) && checkprefix("Content-disposition:", str)) {
+ const char *p = str + 20;
+
+ /* look for the 'filename=' parameter
+ (encoded filenames (*=) are not supported) */
+ for(;;) {
+ char *filename;
+ size_t len;
+
+ while(*p && (p < end) && !ISALPHA(*p))
+ p++;
+ if(p > end - 9)
+ break;
+
+ if(memcmp(p, "filename=", 9)) {
+ /* no match, find next parameter */
+ while((p < end) && (*p != ';'))
+ p++;
+ continue;
+ }
+ p += 9;
+
+ /* this expression below typecasts 'cb' only to avoid
+ warning: signed and unsigned type in conditional expression
+ */
+ len = (ssize_t)cb - (p - str);
+ filename = parse_filename(p, len);
+ if(filename) {
+ outs->filename = filename;
+ outs->alloc_filename = TRUE;
+ outs->is_cd_filename = TRUE;
+ outs->s_isreg = TRUE;
+ outs->fopened = FALSE;
+ outs->stream = NULL;
+ hdrcbdata->honor_cd_filename = FALSE;
+ break;
+ }
+ else
+ return failure;
+ }
+ }
+
+ return cb;
+}
+
+/*
+ * Copies a file name part and returns an ALLOCATED data buffer.
+ */
+static char *parse_filename(const char *ptr, size_t len)
+{
+ char *copy;
+ char *p;
+ char *q;
+ char stop = '\0';
+
+ /* simple implementation of strndup() */
+ copy = malloc(len+1);
+ if(!copy)
+ return NULL;
+ memcpy(copy, ptr, len);
+ copy[len] = '\0';
+
+ p = copy;
+ if(*p == '\'' || *p == '"') {
+ /* store the starting quote */
+ stop = *p;
+ p++;
+ }
+ else
+ stop = ';';
+
+ /* if the filename contains a path, only use filename portion */
+ q = strrchr(copy, '/');
+ if(q) {
+ p = q + 1;
+ if(!*p) {
+ Curl_safefree(copy);
+ return NULL;
+ }
+ }
+
+ /* If the filename contains a backslash, only use filename portion. The idea
+ is that even systems that don't handle backslashes as path separators
+ probably want the path removed for convenience. */
+ q = strrchr(p, '\\');
+ if(q) {
+ p = q + 1;
+ if(!*p) {
+ Curl_safefree(copy);
+ return NULL;
+ }
+ }
+
+ /* scan for the end letter and stop there */
+ q = p;
+ while(*q) {
+ if(q[1] && (q[0] == '\\'))
+ q++;
+ else if(q[0] == stop)
+ break;
+ q++;
+ }
+ *q = '\0';
+
+ /* make sure the file name doesn't end in \r or \n */
+ q = strchr(p, '\r');
+ if(q)
+ *q = '\0';
+
+ q = strchr(p, '\n');
+ if(q)
+ *q = '\0';
+
+ if(copy != p)
+ memmove(copy, p, strlen(p) + 1);
+
+ /* in case we built debug enabled, we allow an evironment variable
+ * named CURL_TESTDIR to prefix the given file name to put it into a
+ * specific directory
+ */
+#ifdef DEBUGBUILD
+ {
+ char *tdir = curlx_getenv("CURL_TESTDIR");
+ if(tdir) {
+ char buffer[512]; /* suitably large */
+ snprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy);
+ Curl_safefree(copy);
+ copy = strdup(buffer); /* clone the buffer, we don't use the libcurl
+ aprintf() or similar since we want to use the
+ same memory code as the "real" parse_filename
+ function */
+ curl_free(tdir);
+ }
+ }
+#endif
+
+ return copy;
+}
+
diff --git a/src/tool_cb_hdr.h b/src/tool_cb_hdr.h
new file mode 100644
index 000000000..bd5043139
--- /dev/null
+++ b/src/tool_cb_hdr.h
@@ -0,0 +1,54 @@
+#ifndef HEADER_CURL_TOOL_CB_HDR_H
+#define HEADER_CURL_TOOL_CB_HDR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+/*
+ * curl operates using a single HdrCbData struct variable, a
+ * pointer to this is passed as userdata pointer to tool_header_cb.
+ *
+ * 'outs' member is a pointer to the OutStruct variable used to keep
+ * track of information relative to curl's output writing.
+ *
+ * 'heads' member is a pointer to the OutStruct variable used to keep
+ * track of information relative to header response writing.
+ *
+ * 'honor_cd_filename' member is TRUE when tool_header_cb is allowed
+ * to honor Content-Disposition filename property and accordingly
+ * set 'outs' filename, otherwise FALSE;
+ */
+
+struct HdrCbData {
+ struct OutStruct *outs;
+ struct OutStruct *heads;
+ bool honor_cd_filename;
+};
+
+/*
+** callback for CURLOPT_HEADERFUNCTION
+*/
+
+size_t tool_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata);
+
+#endif /* HEADER_CURL_TOOL_CB_HDR_H */
+
diff --git a/src/tool_cb_prg.c b/src/tool_cb_prg.c
new file mode 100644
index 000000000..7a701b692
--- /dev/null
+++ b/src/tool_cb_prg.c
@@ -0,0 +1,146 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_cb_prg.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+** callback for CURLOPT_PROGRESSFUNCTION
+*/
+
+#define MAX_BARLENGTH 256
+
+int tool_progress_cb(void *clientp,
+ double dltotal, double dlnow,
+ double ultotal, double ulnow)
+{
+ /* The original progress-bar source code was written for curl by Lars Aas,
+ and this new edition inherits some of his concepts. */
+
+ char line[MAX_BARLENGTH+1];
+ char format[40];
+ double frac;
+ double percent;
+ int barwidth;
+ int num;
+ int i;
+
+ struct ProgressData *bar = (struct ProgressData *)clientp;
+
+ /* expected transfer size */
+ curl_off_t total = (curl_off_t)dltotal + (curl_off_t)ultotal +
+ bar->initial_size;
+
+ /* we've come this far */
+ curl_off_t point = (curl_off_t)dlnow + (curl_off_t)ulnow +
+ bar->initial_size;
+
+ if(point > total)
+ /* we have got more than the expected total! */
+ total = point;
+
+ /* simply count invokes */
+ bar->calls++;
+
+ if(total < 1) {
+ curl_off_t prevblock = bar->prev / 1024;
+ curl_off_t thisblock = point / 1024;
+ while(thisblock > prevblock) {
+ fprintf(bar->out, "#");
+ prevblock++;
+ }
+ }
+ else if(point != bar->prev) {
+ frac = (double)point / (double)total;
+ percent = frac * 100.0f;
+ barwidth = bar->width - 7;
+ num = (int) (((double)barwidth) * frac);
+ if(num > MAX_BARLENGTH)
+ num = MAX_BARLENGTH;
+ for(i = 0; i < num; i++)
+ line[i] = '#';
+ line[i] = '\0';
+ snprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth);
+ fprintf(bar->out, format, line, percent);
+ }
+ fflush(bar->out);
+ bar->prev = point;
+
+ return 0;
+}
+
+void progressbarinit(struct ProgressData *bar,
+ struct Configurable *config)
+{
+#ifdef __EMX__
+ /* 20000318 mgs */
+ int scr_size[2];
+#endif
+ char *colp;
+
+ memset(bar, 0, sizeof(struct ProgressData));
+
+ /* pass this through to progress function so
+ * it can display progress towards total file
+ * not just the part that's left. (21-may-03, dbyron) */
+ if(config->use_resume)
+ bar->initial_size = config->resume_from;
+
+/* TODO: get terminal width through ansi escapes or something similar.
+ try to update width when xterm is resized... - 19990617 larsa */
+#ifndef __EMX__
+ /* 20000318 mgs
+ * OS/2 users most likely won't have this env var set, and besides that
+ * we're using our own way to determine screen width */
+ colp = curlx_getenv("COLUMNS");
+ if(colp) {
+ char *endptr;
+ long num = strtol(colp, &endptr, 10);
+ if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 0))
+ bar->width = (int)num;
+ else
+ bar->width = 79;
+ curl_free(colp);
+ }
+ else
+ bar->width = 79;
+#else
+ /* 20000318 mgs
+ * We use this emx library call to get the screen width, and subtract
+ * one from what we got in order to avoid a problem with the cursor
+ * advancing to the next line if we print a string that is as long as
+ * the screen is wide. */
+
+ _scrsize(scr_size);
+ bar->width = scr_size[0] - 1;
+#endif
+
+ bar->out = config->errors;
+}
+
diff --git a/src/tool_cb_prg.h b/src/tool_cb_prg.h
new file mode 100644
index 000000000..81915b2d5
--- /dev/null
+++ b/src/tool_cb_prg.h
@@ -0,0 +1,49 @@
+#ifndef HEADER_CURL_TOOL_CB_PRG_H
+#define HEADER_CURL_TOOL_CB_PRG_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#define CURL_PROGRESS_STATS 0 /* default progress display */
+#define CURL_PROGRESS_BAR 1
+
+struct ProgressData {
+ int calls;
+ curl_off_t prev;
+ int width;
+ FILE *out; /* where to write everything to */
+ curl_off_t initial_size;
+};
+
+void progressbarinit(struct ProgressData *bar,
+ struct Configurable *config);
+
+/*
+** callback for CURLOPT_PROGRESSFUNCTION
+*/
+
+int tool_progress_cb(void *clientp,
+ double dltotal, double dlnow,
+ double ultotal, double ulnow);
+
+#endif /* HEADER_CURL_TOOL_CB_PRG_H */
+
diff --git a/src/tool_cb_rea.c b/src/tool_cb_rea.c
new file mode 100644
index 000000000..5320cdb30
--- /dev/null
+++ b/src/tool_cb_rea.c
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_cb_rea.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+** callback for CURLOPT_READFUNCTION
+*/
+
+size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata)
+{
+ ssize_t rc;
+ struct InStruct *in = userdata;
+
+ rc = read(in->fd, buffer, sz*nmemb);
+ if(rc < 0) {
+ if(errno == EAGAIN) {
+ errno = 0;
+ in->config->readbusy = TRUE;
+ return CURL_READFUNC_PAUSE;
+ }
+ /* since size_t is unsigned we can't return negative values fine */
+ rc = 0;
+ }
+ in->config->readbusy = FALSE;
+ return (size_t)rc;
+}
+
diff --git a/src/tool_cb_rea.h b/src/tool_cb_rea.h
new file mode 100644
index 000000000..4294166a7
--- /dev/null
+++ b/src/tool_cb_rea.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_TOOL_CB_REA_H
+#define HEADER_CURL_TOOL_CB_REA_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+/*
+** callback for CURLOPT_READFUNCTION
+*/
+
+size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata);
+
+#endif /* HEADER_CURL_TOOL_CB_REA_H */
+
diff --git a/src/tool_cb_see.c b/src/tool_cb_see.c
new file mode 100644
index 000000000..af33ad40b
--- /dev/null
+++ b/src/tool_cb_see.c
@@ -0,0 +1,135 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_cb_see.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/* OUR_MAX_SEEK_L has 'long' data type, OUR_MAX_SEEK_O has 'curl_off_t,
+ both represent the same value. Maximum offset used here when we lseek
+ using a 'long' data type offset */
+
+#define OUR_MAX_SEEK_L 2147483647L - 1L
+#define OUR_MAX_SEEK_O CURL_OFF_T_C(0x7FFFFFFF) - CURL_OFF_T_C(0x1)
+
+/*
+** callback for CURLOPT_SEEKFUNCTION
+**
+** Notice that this is not supposed to return the resulting offset. This
+** shall only return CURL_SEEKFUNC_* return codes.
+*/
+
+int tool_seek_cb(void *userdata, curl_off_t offset, int whence)
+{
+ struct InStruct *in = userdata;
+
+#if(CURL_SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
+
+ /* The offset check following here is only interesting if curl_off_t is
+ larger than off_t and we are not using the WIN32 large file support
+ macros that provide the support to do 64bit seeks correctly */
+
+ if(offset > OUR_MAX_SEEK_O) {
+ /* Some precaution code to work around problems with different data sizes
+ to allow seeking >32bit even if off_t is 32bit. Should be very rare and
+ is really valid on weirdo-systems. */
+ curl_off_t left = offset;
+
+ if(whence != SEEK_SET)
+ /* this code path doesn't support other types */
+ return CURL_SEEKFUNC_FAIL;
+
+ if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET))
+ /* couldn't rewind to beginning */
+ return CURL_SEEKFUNC_FAIL;
+
+ while(left) {
+ long step = (left > OUR_MAX_SEEK_O) ? OUR_MAX_SEEK_L : (long)left;
+ if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR))
+ /* couldn't seek forwards the desired amount */
+ return CURL_SEEKFUNC_FAIL;
+ left -= step;
+ }
+ return CURL_SEEKFUNC_OK;
+ }
+#endif
+
+ if(LSEEK_ERROR == lseek(in->fd, offset, whence))
+ /* couldn't rewind, the reason is in errno but errno is just not portable
+ enough and we don't actually care that much why we failed. We'll let
+ libcurl know that it may try other means if it wants to. */
+ return CURL_SEEKFUNC_CANTSEEK;
+
+ return CURL_SEEKFUNC_OK;
+}
+
+#if defined(WIN32) && !defined(__MINGW64__)
+
+#ifdef __BORLANDC__
+/* 64-bit lseek-like function unavailable */
+# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
+#endif
+
+#ifdef __POCC__
+# if(__POCC__ < 450)
+/* 64-bit lseek-like function unavailable */
+# define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence)
+# else
+# define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence)
+# endif
+#endif
+
+#ifdef _WIN32_WCE
+/* 64-bit lseek-like function unavailable */
+# undef _lseeki64
+# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
+# undef _get_osfhandle
+# define _get_osfhandle(fd) (fd)
+#endif
+
+/*
+ * Truncate a file handle at a 64-bit position 'where'.
+ */
+
+int tool_ftruncate64(int fd, curl_off_t where)
+{
+ if(_lseeki64(fd, where, SEEK_SET) < 0)
+ return -1;
+
+ if(!SetEndOfFile((HANDLE)_get_osfhandle(fd)))
+ return -1;
+
+ return 0;
+}
+
+#endif /* WIN32 && ! __MINGW64__ */
+
diff --git a/src/tool_cb_see.h b/src/tool_cb_see.h
new file mode 100644
index 000000000..ceb22d65c
--- /dev/null
+++ b/src/tool_cb_see.h
@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_TOOL_CB_SEE_H
+#define HEADER_CURL_TOOL_CB_SEE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#if defined(WIN32) && !defined(__MINGW64__)
+
+int tool_ftruncate64(int fd, curl_off_t where);
+
+#undef ftruncate
+#define ftruncate(fd,where) tool_ftruncate64(fd,where)
+
+#ifndef HAVE_FTRUNCATE
+# define HAVE_FTRUNCATE 1
+#endif
+
+#endif /* WIN32 && ! __MINGW64__ */
+
+/*
+** callback for CURLOPT_SEEKFUNCTION
+*/
+
+int tool_seek_cb(void *userdata, curl_off_t offset, int whence);
+
+#endif /* HEADER_CURL_TOOL_CB_SEE_H */
+
diff --git a/src/tool_cb_wrt.c b/src/tool_cb_wrt.c
new file mode 100644
index 000000000..d6688110a
--- /dev/null
+++ b/src/tool_cb_wrt.c
@@ -0,0 +1,152 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+#include "tool_cb_wrt.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+** callback for CURLOPT_WRITEFUNCTION
+*/
+
+size_t tool_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata)
+{
+ size_t rc;
+ struct OutStruct *outs = userdata;
+ struct Configurable *config = outs->config;
+
+ /*
+ * Once that libcurl has called back tool_write_cb() the returned value
+ * is checked against the amount that was intended to be written, if
+ * it does not match then it fails with CURLE_WRITE_ERROR. So at this
+ * point returning a value different from sz*nmemb indicates failure.
+ */
+ const size_t failure = (sz * nmemb) ? 0 : 1;
+
+ if(!config)
+ return failure;
+
+#ifdef DEBUGBUILD
+ if(config->include_headers) {
+ if(sz * nmemb > (size_t)CURL_MAX_HTTP_HEADER) {
+ warnf(config, "Header data size exceeds single call write limit!\n");
+ return failure;
+ }
+ }
+ else {
+ if(sz * nmemb > (size_t)CURL_MAX_WRITE_SIZE) {
+ warnf(config, "Data size exceeds single call write limit!\n");
+ return failure;
+ }
+ }
+
+ {
+ /* Some internal congruency checks on received OutStruct */
+ bool check_fails = FALSE;
+ if(outs->filename) {
+ /* regular file */
+ if(!*outs->filename)
+ check_fails = TRUE;
+ if(!outs->s_isreg)
+ check_fails = TRUE;
+ if(outs->fopened && !outs->stream)
+ check_fails = TRUE;
+ if(!outs->fopened && outs->stream)
+ check_fails = TRUE;
+ if(!outs->fopened && outs->bytes)
+ check_fails = TRUE;
+ }
+ else {
+ /* standard stream */
+ if(!outs->stream || outs->s_isreg || outs->fopened)
+ check_fails = TRUE;
+ if(outs->alloc_filename || outs->is_cd_filename || outs->init)
+ check_fails = TRUE;
+ }
+ if(check_fails) {
+ warnf(config, "Invalid output struct data for write callback\n");
+ return failure;
+ }
+ }
+#endif
+
+ if(!outs->stream) {
+ FILE *file;
+
+ if(!outs->filename || !*outs->filename) {
+ warnf(config, "Remote filename has no length!\n");
+ return failure;
+ }
+
+ if(outs->is_cd_filename) {
+ /* don't overwrite existing files */
+ file = fopen(outs->filename, "rb");
+ if(file) {
+ fclose(file);
+ warnf(config, "Refusing to overwrite %s: %s\n", outs->filename,
+ strerror(EEXIST));
+ return failure;
+ }
+ }
+
+ /* open file for writing */
+ file = fopen(outs->filename, "wb");
+ if(!file) {
+ warnf(config, "Failed to create the file %s: %s\n", outs->filename,
+ strerror(errno));
+ return failure;
+ }
+ outs->s_isreg = TRUE;
+ outs->fopened = TRUE;
+ outs->stream = file;
+ outs->bytes = 0;
+ outs->init = 0;
+ }
+
+ rc = fwrite(buffer, sz, nmemb, outs->stream);
+
+ if((sz * nmemb) == rc)
+ /* we added this amount of data to the output */
+ outs->bytes += (sz * nmemb);
+
+ if(config->readbusy) {
+ config->readbusy = FALSE;
+ curl_easy_pause(config->easy, CURLPAUSE_CONT);
+ }
+
+ if(config->nobuffer) {
+ /* output buffering disabled */
+ int res = fflush(outs->stream);
+ if(res)
+ return failure;
+ }
+
+ return rc;
+}
+
diff --git a/src/tool_cb_wrt.h b/src/tool_cb_wrt.h
new file mode 100644
index 000000000..380d8dd6a
--- /dev/null
+++ b/src/tool_cb_wrt.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_TOOL_CB_WRT_H
+#define HEADER_CURL_TOOL_CB_WRT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+/*
+** callback for CURLOPT_WRITEFUNCTION
+*/
+
+size_t tool_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata);
+
+#endif /* HEADER_CURL_TOOL_CB_WRT_H */
+
diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c
new file mode 100644
index 000000000..da11f4afe
--- /dev/null
+++ b/src/tool_cfgable.c
@@ -0,0 +1,128 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "tool_cfgable.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+void free_config_fields(struct Configurable *config)
+{
+ struct getout *urlnode;
+
+ if(config->easy) {
+ curl_easy_cleanup(config->easy);
+ config->easy = NULL;
+ }
+
+ Curl_safefree(config->random_file);
+ Curl_safefree(config->egd_file);
+ Curl_safefree(config->useragent);
+ Curl_safefree(config->cookie);
+ Curl_safefree(config->cookiejar);
+ Curl_safefree(config->cookiefile);
+
+ Curl_safefree(config->postfields);
+ Curl_safefree(config->referer);
+
+ Curl_safefree(config->headerfile);
+ Curl_safefree(config->ftpport);
+ Curl_safefree(config->iface);
+
+ Curl_safefree(config->range);
+
+ Curl_safefree(config->userpwd);
+ Curl_safefree(config->tls_username);
+ Curl_safefree(config->tls_password);
+ Curl_safefree(config->tls_authtype);
+ Curl_safefree(config->proxyuserpwd);
+ Curl_safefree(config->proxy);
+
+ Curl_safefree(config->noproxy);
+
+ Curl_safefree(config->mail_from);
+ curl_slist_free_all(config->mail_rcpt);
+ Curl_safefree(config->mail_auth);
+
+ Curl_safefree(config->netrc_file);
+
+ urlnode = config->url_list;
+ while(urlnode) {
+ struct getout *next = urlnode->next;
+ Curl_safefree(urlnode->url);
+ Curl_safefree(urlnode->outfile);
+ Curl_safefree(urlnode->infile);
+ Curl_safefree(urlnode);
+ urlnode = next;
+ }
+ config->url_list = NULL;
+ config->url_last = NULL;
+ config->url_get = NULL;
+ config->url_out = NULL;
+
+ Curl_safefree(config->cipher_list);
+ Curl_safefree(config->cert);
+ Curl_safefree(config->cert_type);
+ Curl_safefree(config->cacert);
+ Curl_safefree(config->capath);
+ Curl_safefree(config->crlfile);
+ Curl_safefree(config->key);
+ Curl_safefree(config->key_type);
+ Curl_safefree(config->key_passwd);
+ Curl_safefree(config->pubkey);
+ Curl_safefree(config->hostpubmd5);
+ Curl_safefree(config->engine);
+
+ Curl_safefree(config->customrequest);
+ Curl_safefree(config->krblevel);
+ Curl_safefree(config->trace_dump);
+
+ config->trace_stream = NULL; /* closed elsewhere when appropriate */
+
+ Curl_safefree(config->writeout);
+
+ config->errors = NULL; /* closed elsewhere when appropriate */
+
+ curl_slist_free_all(config->quote);
+ curl_slist_free_all(config->postquote);
+ curl_slist_free_all(config->prequote);
+
+ curl_slist_free_all(config->headers);
+
+ if(config->httppost) {
+ curl_formfree(config->httppost);
+ config->httppost = NULL;
+ }
+ config->last_post = NULL;
+
+ curl_slist_free_all(config->telnet_options);
+ curl_slist_free_all(config->resolve);
+
+ Curl_safefree(config->socksproxy);
+ Curl_safefree(config->socks5_gssapi_service);
+
+ Curl_safefree(config->ftp_account);
+ Curl_safefree(config->ftp_alternative_to_user);
+
+ Curl_safefree(config->libcurl);
+}
+
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
new file mode 100644
index 000000000..1f6f94852
--- /dev/null
+++ b/src/tool_cfgable.h
@@ -0,0 +1,212 @@
+#ifndef HEADER_CURL_TOOL_CFGABLE_H
+#define HEADER_CURL_TOOL_CFGABLE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "tool_sdecls.h"
+
+#include "tool_metalink.h"
+
+struct Configurable {
+ CURL *easy; /* once we have one, we keep it here */
+ bool remote_time;
+ char *random_file;
+ char *egd_file;
+ char *useragent;
+ char *cookie; /* single line with specified cookies */
+ char *cookiejar; /* write to this file */
+ char *cookiefile; /* read from this file */
+ bool cookiesession; /* new session? */
+ bool encoding; /* Accept-Encoding please */
+ bool tr_encoding; /* Transfer-Encoding please */
+ unsigned long authtype; /* auth bitmask */
+ bool use_resume;
+ bool resume_from_current;
+ bool disable_epsv;
+ bool disable_eprt;
+ bool ftp_pret;
+ long proto;
+ bool proto_present;
+ long proto_redir;
+ bool proto_redir_present;
+ curl_off_t resume_from;
+ char *postfields;
+ curl_off_t postfieldsize;
+ char *referer;
+ long timeout;
+ long connecttimeout;
+ long maxredirs;
+ curl_off_t max_filesize;
+ char *headerfile;
+ char *ftpport;
+ char *iface;
+ int localport;
+ int localportrange;
+ unsigned short porttouse;
+ char *range;
+ long low_speed_limit;
+ long low_speed_time;
+ int showerror; /* -1 == unset, default => show errors
+ 0 => -s is used to NOT show errors
+ 1 => -S has been used to show errors */
+ char *userpwd;
+ char *tls_username;
+ char *tls_password;
+ char *tls_authtype;
+ char *proxyuserpwd;
+ char *proxy;
+ int proxyver; /* set to CURLPROXY_HTTP* define */
+ char *noproxy;
+ char *mail_from;
+ struct curl_slist *mail_rcpt;
+ char *mail_auth;
+ bool proxytunnel;
+ bool ftp_append; /* APPE on ftp */
+ bool mute; /* don't show messages, --silent given */
+ bool use_ascii; /* select ascii or text transfer */
+ bool autoreferer; /* automatically set referer */
+ bool failonerror; /* fail on (HTTP) errors */
+ bool include_headers; /* send headers to data output */
+ bool no_body; /* don't get the body */
+ bool dirlistonly; /* only get the FTP dir list */
+ bool followlocation; /* follow http redirects */
+ bool unrestricted_auth; /* Continue to send authentication (user+password)
+ when following ocations, even when hostname
+ changed */
+ bool netrc_opt;
+ bool netrc;
+ char *netrc_file;
+ bool noprogress; /* don't show progress meter, --silent given */
+ bool isatty; /* updated internally only if output is a tty */
+ struct getout *url_list; /* point to the first node */
+ struct getout *url_last; /* point to the last/current node */
+ struct getout *url_get; /* point to the node to fill in URL */
+ struct getout *url_out; /* point to the node to fill in outfile */
+ char *cipher_list;
+ char *cert;
+ char *cert_type;
+ char *cacert;
+ char *capath;
+ char *crlfile;
+ char *key;
+ char *key_type;
+ char *key_passwd;
+ char *pubkey;
+ char *hostpubmd5;
+ char *engine;
+ bool list_engines;
+ bool crlf;
+ char *customrequest;
+ char *krblevel;
+ char *trace_dump; /* file to dump the network trace to, or NULL */
+ FILE *trace_stream;
+ bool trace_fopened;
+ trace tracetype;
+ bool tracetime; /* include timestamp? */
+ long httpversion;
+ int progressmode; /* CURL_PROGRESS_BAR or CURL_PROGRESS_STATS */
+ bool nobuffer;
+ bool readbusy; /* set when reading input returns EAGAIN */
+ bool globoff;
+ bool use_httpget;
+ bool insecure_ok; /* set TRUE to allow insecure SSL connects */
+ bool create_dirs;
+ bool ftp_create_dirs;
+ bool ftp_skip_ip;
+ bool proxynegotiate;
+ bool proxyntlm;
+ bool proxydigest;
+ bool proxybasic;
+ bool proxyanyauth;
+ char *writeout; /* %-styled format string to output */
+ bool writeenv; /* write results to environment, if available */
+ FILE *errors; /* errors stream, defaults to stderr */
+ bool errors_fopened; /* whether errors stream isn't stderr */
+ struct curl_slist *quote;
+ struct curl_slist *postquote;
+ struct curl_slist *prequote;
+ long ssl_version;
+ long ip_version;
+ curl_TimeCond timecond;
+ time_t condtime;
+ struct curl_slist *headers;
+ struct curl_httppost *httppost;
+ struct curl_httppost *last_post;
+ struct curl_slist *telnet_options;
+ struct curl_slist *resolve;
+ HttpReq httpreq;
+
+ /* for bandwidth limiting features: */
+ curl_off_t sendpersecond; /* send to peer */
+ curl_off_t recvpersecond; /* receive from peer */
+
+ bool ftp_ssl;
+ bool ftp_ssl_reqd;
+ bool ftp_ssl_control;
+ bool ftp_ssl_ccc;
+ int ftp_ssl_ccc_mode;
+
+ char *socksproxy; /* set to server string */
+ int socksver; /* set to CURLPROXY_SOCKS* define */
+ char *socks5_gssapi_service; /* set service name for gssapi principal
+ * default rcmd */
+ int socks5_gssapi_nec ; /* The NEC reference server does not protect
+ * the encryption type exchange */
+
+ bool tcp_nodelay;
+ long req_retry; /* number of retries */
+ long retry_delay; /* delay between retries (in seconds) */
+ long retry_maxtime; /* maximum time to keep retrying */
+
+ char *ftp_account; /* for ACCT */
+ char *ftp_alternative_to_user; /* send command if USER/PASS fails */
+ int ftp_filemethod;
+ long tftp_blksize; /* TFTP BLKSIZE option */
+ bool ignorecl; /* --ignore-content-length */
+ bool disable_sessionid;
+
+ char *libcurl; /* output libcurl code to this file name */
+ bool raw;
+ bool post301;
+ bool post302;
+ bool post303;
+ bool nokeepalive; /* for keepalive needs */
+ long alivetime;
+ bool content_disposition; /* use Content-disposition filename */
+
+ int default_node_flags; /* default flags to search for each 'node', which
+ is basically each given URL to transfer */
+
+ bool xattr; /* store metadata in extended attributes */
+ long gssapi_delegation;
+ bool ssl_allow_beast; /* allow this SSL vulnerability */
+
+ bool use_metalink; /* process given URLs as metalink XML file */
+ metalinkfile *metalinkfile_list; /* point to the first node */
+ metalinkfile *metalinkfile_last; /* point to the last/current node */
+}; /* struct Configurable */
+
+void free_config_fields(struct Configurable *config);
+
+#endif /* HEADER_CURL_TOOL_CFGABLE_H */
+
diff --git a/src/tool_convert.c b/src/tool_convert.c
new file mode 100644
index 000000000..ecce036a0
--- /dev/null
+++ b/src/tool_convert.c
@@ -0,0 +1,150 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef CURL_DOES_CONVERSIONS
+
+#ifdef HAVE_ICONV
+# include <iconv.h>
+#endif
+
+#include "tool_convert.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef HAVE_ICONV
+
+/* curl tool iconv conversion descriptors */
+static iconv_t inbound_cd = (iconv_t)-1;
+static iconv_t outbound_cd = (iconv_t)-1;
+
+/* set default codesets for iconv */
+#ifndef CURL_ICONV_CODESET_OF_NETWORK
+# define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
+#endif
+
+/*
+ * convert_to_network() is a curl tool function to convert
+ * from the host encoding to ASCII on non-ASCII platforms.
+ */
+CURLcode convert_to_network(char *buffer, size_t length)
+{
+ /* translate from the host encoding to the network encoding */
+ char *input_ptr, *output_ptr;
+ size_t res, in_bytes, out_bytes;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(outbound_cd == (iconv_t)-1) {
+ outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST);
+ if(outbound_cd == (iconv_t)-1) {
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ res = iconv(outbound_cd, &input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if((res == (size_t)-1) || (in_bytes != 0)) {
+ return CURLE_CONV_FAILED;
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * convert_from_network() is a curl tool function
+ * for performing ASCII conversions on non-ASCII platforms.
+ */
+CURLcode convert_from_network(char *buffer, size_t length)
+{
+ /* translate from the network encoding to the host encoding */
+ char *input_ptr, *output_ptr;
+ size_t res, in_bytes, out_bytes;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(inbound_cd == (iconv_t)-1) {
+ inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK);
+ if(inbound_cd == (iconv_t)-1) {
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ res = iconv(inbound_cd, &input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if((res == (size_t)-1) || (in_bytes != 0)) {
+ return CURLE_CONV_FAILED;
+ }
+
+ return CURLE_OK;
+}
+
+void convert_cleanup(void)
+{
+ /* close iconv conversion descriptors */
+ if(inbound_cd != (iconv_t)-1)
+ (void)iconv_close(inbound_cd);
+ if(outbound_cd != (iconv_t)-1)
+ (void)iconv_close(outbound_cd);
+}
+
+#endif /* HAVE_ICONV */
+
+char convert_char(curl_infotype infotype, char this_char)
+{
+/* determine how this specific character should be displayed */
+ switch(infotype) {
+ case CURLINFO_DATA_IN:
+ case CURLINFO_DATA_OUT:
+ case CURLINFO_SSL_DATA_IN:
+ case CURLINFO_SSL_DATA_OUT:
+ /* data, treat as ASCII */
+ if((this_char >= 0x20) && (this_char < 0x7f)) {
+ /* printable ASCII hex value: convert to host encoding */
+ (void)convert_from_network(&this_char, 1);
+ }
+ else {
+ /* non-printable ASCII, use a replacement character */
+ return UNPRINTABLE_CHAR;
+ }
+ /* fall through to default */
+ default:
+ /* treat as host encoding */
+ if(ISPRINT(this_char)
+ && (this_char != '\t')
+ && (this_char != '\r')
+ && (this_char != '\n')) {
+ /* printable characters excluding tabs and line end characters */
+ return this_char;
+ }
+ break;
+ }
+ /* non-printable, use a replacement character */
+ return UNPRINTABLE_CHAR;
+}
+
+#endif /* CURL_DOES_CONVERSIONS */
+
diff --git a/src/tool_convert.h b/src/tool_convert.h
new file mode 100644
index 000000000..32d473f97
--- /dev/null
+++ b/src/tool_convert.h
@@ -0,0 +1,45 @@
+#ifndef HEADER_CURL_TOOL_CONVERT_H
+#define HEADER_CURL_TOOL_CONVERT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef CURL_DOES_CONVERSIONS
+
+#ifdef HAVE_ICONV
+
+CURLcode convert_to_network(char *buffer, size_t length);
+CURLcode convert_from_network(char *buffer, size_t length);
+void convert_cleanup(void);
+
+#endif /* HAVE_ICONV */
+
+char convert_char(curl_infotype infotype, char this_char);
+
+#endif /* CURL_DOES_CONVERSIONS */
+
+#if !defined(CURL_DOES_CONVERSIONS) || !defined(HAVE_ICONV)
+#define convert_cleanup() Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_TOOL_CONVERT_H */
+
diff --git a/src/tool_dirhie.c b/src/tool_dirhie.c
new file mode 100644
index 000000000..d21dc97c6
--- /dev/null
+++ b/src/tool_dirhie.c
@@ -0,0 +1,149 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef WIN32
+# include <direct.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_dirhie.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef NETWARE
+# ifndef __NOVELL_LIBC__
+# define mkdir mkdir_510
+# endif
+#endif
+
+#ifdef WIN32
+# define mkdir(x,y) (mkdir)((x))
+# ifndef __POCC__
+# define F_OK 0
+# endif
+#endif
+
+static void show_dir_errno(FILE *errors, const char *name)
+{
+ switch(ERRNO) {
+#ifdef EACCES
+ case EACCES:
+ fprintf(errors, "You don't have permission to create %s.\n", name);
+ break;
+#endif
+#ifdef ENAMETOOLONG
+ case ENAMETOOLONG:
+ fprintf(errors, "The directory name %s is too long.\n", name);
+ break;
+#endif
+#ifdef EROFS
+ case EROFS:
+ fprintf(errors, "%s resides on a read-only file system.\n", name);
+ break;
+#endif
+#ifdef ENOSPC
+ case ENOSPC:
+ fprintf(errors, "No space left on the file system that will "
+ "contain the directory %s.\n", name);
+ break;
+#endif
+#ifdef EDQUOT
+ case EDQUOT:
+ fprintf(errors, "Cannot create directory %s because you "
+ "exceeded your quota.\n", name);
+ break;
+#endif
+ default :
+ fprintf(errors, "Error creating directory %s.\n", name);
+ break;
+ }
+}
+
+/*
+ * Create the needed directory hierarchy recursively in order to save
+ * multi-GETs in file output, ie:
+ * curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
+ * should create all the dir* automagically
+ */
+
+CURLcode create_dir_hierarchy(const char *outfile, FILE *errors)
+{
+ char *tempdir;
+ char *tempdir2;
+ char *outdup;
+ char *dirbuildup;
+ CURLcode result = CURLE_OK;
+
+ outdup = strdup(outfile);
+ if(!outdup)
+ return CURLE_OUT_OF_MEMORY;
+
+ dirbuildup = malloc(strlen(outfile) + 1);
+ if(!dirbuildup) {
+ Curl_safefree(outdup);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ dirbuildup[0] = '\0';
+
+ tempdir = strtok(outdup, DIR_CHAR);
+
+ while(tempdir != NULL) {
+ tempdir2 = strtok(NULL, DIR_CHAR);
+ /* since strtok returns a token for the last word even
+ if not ending with DIR_CHAR, we need to prune it */
+ if(tempdir2 != NULL) {
+ size_t dlen = strlen(dirbuildup);
+ if(dlen)
+ sprintf(&dirbuildup[dlen], "%s%s", DIR_CHAR, tempdir);
+ else {
+ if(0 != strncmp(outdup, DIR_CHAR, 1))
+ strcpy(dirbuildup, tempdir);
+ else
+ sprintf(dirbuildup, "%s%s", DIR_CHAR, tempdir);
+ }
+ if(access(dirbuildup, F_OK) == -1) {
+ if(-1 == mkdir(dirbuildup,(mode_t)0000750)) {
+ show_dir_errno(errors, dirbuildup);
+ result = CURLE_WRITE_ERROR;
+ break; /* get out of loop */
+ }
+ }
+ }
+ tempdir = tempdir2;
+ }
+
+ Curl_safefree(dirbuildup);
+ Curl_safefree(outdup);
+
+ return result;
+}
+
diff --git a/src/tool_dirhie.h b/src/tool_dirhie.h
new file mode 100644
index 000000000..5f19575d4
--- /dev/null
+++ b/src/tool_dirhie.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TOOL_DIRHIE_H
+#define HEADER_CURL_TOOL_DIRHIE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+CURLcode create_dir_hierarchy(const char *outfile, FILE *errors);
+
+#endif /* HEADER_CURL_TOOL_DIRHIE_H */
+
diff --git a/src/tool_doswin.c b/src/tool_doswin.c
new file mode 100644
index 000000000..4fae91d32
--- /dev/null
+++ b/src/tool_doswin.c
@@ -0,0 +1,299 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#if defined(MSDOS) || defined(WIN32)
+
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+# include <libgen.h>
+#endif
+
+#ifdef WIN32
+# include "tool_cfgable.h"
+# include "tool_libinfo.h"
+#endif
+
+#include "tool_bname.h"
+#include "tool_doswin.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+ * Macros ALWAYS_TRUE and ALWAYS_FALSE are used to avoid compiler warnings.
+ */
+
+#define ALWAYS_TRUE (1)
+#define ALWAYS_FALSE (0)
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+# undef ALWAYS_TRUE
+# undef ALWAYS_FALSE
+# if (_MSC_VER < 1500)
+# define ALWAYS_TRUE (0, 1)
+# define ALWAYS_FALSE (1, 0)
+# else
+# define ALWAYS_TRUE \
+__pragma(warning(push)) \
+__pragma(warning(disable:4127)) \
+(1) \
+__pragma(warning(pop))
+# define ALWAYS_FALSE \
+__pragma(warning(push)) \
+__pragma(warning(disable:4127)) \
+(0) \
+__pragma(warning(pop))
+# endif
+#endif
+
+#ifdef WIN32
+# undef PATH_MAX
+# define PATH_MAX MAX_PATH
+#endif
+
+#ifndef S_ISCHR
+# ifdef S_IFCHR
+# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+# else
+# define S_ISCHR(m) (0) /* cannot tell if file is a device */
+# endif
+#endif
+
+#ifdef WIN32
+# define _use_lfn(f) ALWAYS_TRUE /* long file names always available */
+#elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */
+# define _use_lfn(f) ALWAYS_FALSE /* long file names never available */
+#elif defined(__DJGPP__)
+# include <fcntl.h> /* _use_lfn(f) prototype */
+#endif
+
+static const char *msdosify (const char *file_name);
+static char *rename_if_dos_device_name (char *file_name);
+
+/*
+ * sanitize_dos_name: returns a newly allocated string holding a
+ * valid file name which will be a transformation of given argument
+ * in case this wasn't already a valid file name.
+ *
+ * This function takes ownership of given argument, free'ing it before
+ * returning. Caller is responsible of free'ing returned string. Upon
+ * out of memory condition function returns NULL.
+ */
+
+char *sanitize_dos_name(char *file_name)
+{
+ char new_name[PATH_MAX];
+
+ if(!file_name)
+ return NULL;
+
+ if(strlen(file_name) >= PATH_MAX)
+ file_name[PATH_MAX-1] = '\0'; /* truncate it */
+
+ strcpy(new_name, msdosify(file_name));
+
+ Curl_safefree(file_name);
+
+ return strdup(rename_if_dos_device_name(new_name));
+}
+
+/* The following functions are taken with modification from the DJGPP
+ * port of tar 1.12. They use algorithms originally from DJTAR. */
+
+static const char *msdosify (const char *file_name)
+{
+ static char dos_name[PATH_MAX];
+ static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
+ "|<>\\\":?*"; /* illegal in DOS & W95 */
+ static const char *illegal_chars_w95 = &illegal_chars_dos[8];
+ int idx, dot_idx;
+ const char *s = file_name;
+ char *d = dos_name;
+ const char *const dlimit = dos_name + sizeof(dos_name) - 1;
+ const char *illegal_aliens = illegal_chars_dos;
+ size_t len = sizeof(illegal_chars_dos) - 1;
+
+ /* Support for Windows 9X VFAT systems, when available. */
+ if(_use_lfn(file_name)) {
+ illegal_aliens = illegal_chars_w95;
+ len -= (illegal_chars_w95 - illegal_chars_dos);
+ }
+
+ /* Get past the drive letter, if any. */
+ if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
+ if(memchr(illegal_aliens, *s, len)) {
+ /* Dots are special: DOS doesn't allow them as the leading character,
+ and a file name cannot have more than a single dot. We leave the
+ first non-leading dot alone, unless it comes too close to the
+ beginning of the name: we want sh.lex.c to become sh_lex.c, not
+ sh.lex-c. */
+ if(*s == '.') {
+ if(idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) {
+ /* Copy "./" and "../" verbatim. */
+ *d++ = *s++;
+ if(*s == '.')
+ *d++ = *s++;
+ *d = *s;
+ }
+ else if(idx == 0)
+ *d = '_';
+ else if(dot_idx >= 0) {
+ if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
+ d[dot_idx - idx] = '_'; /* replace previous dot */
+ *d = '.';
+ }
+ else
+ *d = '-';
+ }
+ else
+ *d = '.';
+
+ if(*s == '.')
+ dot_idx = idx;
+ }
+ else if(*s == '+' && s[1] == '+') {
+ if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */
+ *d++ = 'x';
+ *d = 'x';
+ }
+ else {
+ /* libg++ etc. */
+ memcpy (d, "plus", 4);
+ d += 3;
+ }
+ s++;
+ idx++;
+ }
+ else
+ *d = '_';
+ }
+ else
+ *d = *s;
+ if(*s == '/') {
+ idx = 0;
+ dot_idx = -1;
+ }
+ else
+ idx++;
+ }
+
+ *d = '\0';
+ return dos_name;
+}
+
+static char *rename_if_dos_device_name (char *file_name)
+{
+ /* We could have a file whose name is a device on MS-DOS. Trying to
+ * retrieve such a file would fail at best and wedge us at worst. We need
+ * to rename such files. */
+ char *base;
+ struct_stat st_buf;
+ char fname[PATH_MAX];
+
+ strncpy(fname, file_name, PATH_MAX-1);
+ fname[PATH_MAX-1] = '\0';
+ base = basename(fname);
+ if(((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
+ size_t blen = strlen(base);
+
+ if(strlen(fname) >= PATH_MAX-1) {
+ /* Make room for the '_' */
+ blen--;
+ base[blen] = '\0';
+ }
+ /* Prepend a '_'. */
+ memmove(base + 1, base, blen + 1);
+ base[0] = '_';
+ strcpy(file_name, fname);
+ }
+ return file_name;
+}
+
+#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__))
+
+/*
+ * Disable program default argument globbing. We do it on our own.
+ */
+char **__crt0_glob_function(char *arg)
+{
+ (void)arg;
+ return (char**)0;
+}
+
+#endif /* MSDOS && (__DJGPP__ || __GO32__) */
+
+#ifdef WIN32
+
+/*
+ * Function to find CACert bundle on a Win32 platform using SearchPath.
+ * (SearchPath is already declared via inclusions done in setup header file)
+ * (Use the ASCII version instead of the unicode one!)
+ * The order of the directories it searches is:
+ * 1. application's directory
+ * 2. current working directory
+ * 3. Windows System directory (e.g. C:\windows\system32)
+ * 4. Windows Directory (e.g. C:\windows)
+ * 5. all directories along %PATH%
+ *
+ * For WinXP and later search order actually depends on registry value:
+ * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode
+ */
+
+CURLcode FindWin32CACert(struct Configurable *config, const char *bundle_file)
+{
+ CURLcode result = CURLE_OK;
+
+ /* search and set cert file only if libcurl supports SSL */
+ if(curlinfo->features & CURL_VERSION_SSL) {
+
+ DWORD res_len;
+ DWORD buf_tchar_size = PATH_MAX + 1;
+ DWORD buf_bytes_size = sizeof(TCHAR) * buf_tchar_size;
+ char *ptr = NULL;
+
+ char *buf = malloc(buf_bytes_size);
+ if(!buf)
+ return CURLE_OUT_OF_MEMORY;
+ buf[0] = '\0';
+
+ res_len = SearchPathA(NULL, bundle_file, NULL, buf_tchar_size, buf, &ptr);
+ if(res_len > 0) {
+ Curl_safefree(config->cacert);
+ config->cacert = strdup(buf);
+ if(!config->cacert)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ Curl_safefree(buf);
+ }
+
+ return result;
+}
+
+#endif /* WIN32 */
+
+#endif /* MSDOS || WIN32 */
+
diff --git a/src/tool_doswin.h b/src/tool_doswin.h
new file mode 100644
index 000000000..955ce8d38
--- /dev/null
+++ b/src/tool_doswin.h
@@ -0,0 +1,45 @@
+#ifndef HEADER_CURL_TOOL_DOSWIN_H
+#define HEADER_CURL_TOOL_DOSWIN_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#if defined(MSDOS) || defined(WIN32)
+
+char *sanitize_dos_name(char *file_name);
+
+#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__))
+
+char **__crt0_glob_function(char *arg);
+
+#endif /* MSDOS && (__DJGPP__ || __GO32__) */
+
+#ifdef WIN32
+
+CURLcode FindWin32CACert(struct Configurable *config, const char *bundle_file);
+
+#endif /* WIN32 */
+
+#endif /* MSDOS || WIN32 */
+
+#endif /* HEADER_CURL_TOOL_DOSWIN_H */
+
diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c
new file mode 100644
index 000000000..339dde563
--- /dev/null
+++ b/src/tool_easysrc.c
@@ -0,0 +1,227 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifndef CURL_DISABLE_LIBCURL_OPTION
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_easysrc.h"
+#include "tool_msgs.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/* global variable definitions, for easy-interface source code generation */
+
+struct curl_slist *easysrc_decl = NULL; /* Variable declarations */
+struct curl_slist *easysrc_data = NULL; /* Build slists, forms etc. */
+struct curl_slist *easysrc_code = NULL; /* Setopt calls */
+struct curl_slist *easysrc_toohard = NULL; /* Unconvertible setopt */
+struct curl_slist *easysrc_clean = NULL; /* Clean up allocated data */
+int easysrc_form_count = 0;
+int easysrc_slist_count = 0;
+
+static const char *const srchead[]={
+ "/********* Sample code generated by the curl command line tool **********",
+ " * All curl_easy_setopt() options are documented at:",
+ " * http://curl.haxx.se/libcurl/c/curl_easy_setopt.html",
+ " ************************************************************************/",
+ "#include <curl/curl.h>",
+ "",
+ "int main(int argc, char *argv[])",
+ "{",
+ " CURLcode ret;",
+ " CURL *hnd;",
+ NULL
+};
+/* easysrc_decl declarations come here */
+/* easysrc_data initialisations come here */
+/* easysrc_code statements come here */
+static const char *const srchard[]={
+ "/* Here is a list of options the curl code used that cannot get generated",
+ " as source easily. You may select to either not use them or implement",
+ " them yourself.",
+ "",
+ NULL
+};
+static const char *const srcend[]={
+ "",
+ " return (int)ret;",
+ "}",
+ "/**** End of sample code ****/",
+ NULL
+};
+
+/* Clean up all source code if we run out of memory */
+static void easysrc_free(void)
+{
+ curl_slist_free_all(easysrc_decl);
+ easysrc_decl = NULL;
+ curl_slist_free_all(easysrc_data);
+ easysrc_data = NULL;
+ curl_slist_free_all(easysrc_code);
+ easysrc_code = NULL;
+ curl_slist_free_all(easysrc_toohard);
+ easysrc_toohard = NULL;
+ curl_slist_free_all(easysrc_clean);
+ easysrc_clean = NULL;
+}
+
+/* Add a source line to the main code or remarks */
+CURLcode easysrc_add(struct curl_slist **plist, const char *line)
+{
+ CURLcode ret = CURLE_OK;
+ struct curl_slist *list =
+ curl_slist_append(*plist, line);
+ if(!list) {
+ easysrc_free();
+ ret = CURLE_OUT_OF_MEMORY;
+ }
+ else
+ *plist = list;
+ return ret;
+}
+
+CURLcode easysrc_addf(struct curl_slist **plist, const char *fmt, ...)
+{
+ CURLcode ret;
+ char *bufp;
+ va_list ap;
+ va_start(ap, fmt);
+ bufp = curlx_mvaprintf(fmt, ap);
+ va_end(ap);
+ if(! bufp) {
+ ret = CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ ret = easysrc_add(plist, bufp);
+ curl_free(bufp);
+ }
+ return ret;
+}
+
+#define CHKRET(v) do {CURLcode ret = (v); if(ret) return ret;} WHILE_FALSE
+
+CURLcode easysrc_init(void)
+{
+ CHKRET(easysrc_add(&easysrc_code,
+ "hnd = curl_easy_init();"));
+ return CURLE_OK;
+}
+
+CURLcode easysrc_perform(void)
+{
+ /* Note any setopt calls which we could not convert */
+ if(easysrc_toohard) {
+ int i;
+ struct curl_slist *ptr;
+ const char *c;
+ CHKRET(easysrc_add(&easysrc_code, ""));
+ /* Preamble comment */
+ for(i=0; ((c = srchard[i]) != NULL); i++)
+ CHKRET(easysrc_add(&easysrc_code, c));
+ /* Each unconverted option */
+ for(ptr=easysrc_toohard; ptr; ptr = ptr->next)
+ CHKRET(easysrc_add(&easysrc_code, ptr->data));
+ CHKRET(easysrc_add(&easysrc_code, ""));
+ CHKRET(easysrc_add(&easysrc_code, "*/"));
+
+ curl_slist_free_all(easysrc_toohard);
+ easysrc_toohard = NULL;
+ }
+
+ CHKRET(easysrc_add(&easysrc_code, ""));
+ CHKRET(easysrc_add(&easysrc_code, "ret = curl_easy_perform(hnd);"));
+ return CURLE_OK;
+}
+
+CURLcode easysrc_cleanup(void)
+{
+ CHKRET(easysrc_add(&easysrc_code, ""));
+ CHKRET(easysrc_add(&easysrc_code, "curl_easy_cleanup(hnd);"));
+ CHKRET(easysrc_add(&easysrc_code, "hnd = NULL;"));
+ return CURLE_OK;
+}
+
+void dumpeasysrc(struct Configurable *config)
+{
+ struct curl_slist *ptr;
+ char *o = config->libcurl;
+
+ if(o) {
+ FILE *out;
+ bool fopened = FALSE;
+ if(strcmp(o, "-")) {
+ out = fopen(o, "w");
+ fopened = TRUE;
+ }
+ else
+ out = stdout;
+ if(!out)
+ warnf(config, "Failed to open %s to write libcurl code!\n", o);
+ else {
+ int i;
+ const char *c;
+
+ for(i=0; ((c = srchead[i]) != NULL); i++)
+ fprintf(out, "%s\n", c);
+
+ /* Declare variables used for complex setopt values */
+ for(ptr=easysrc_decl; ptr; ptr = ptr->next)
+ fprintf(out, " %s\n", ptr->data);
+
+ /* Set up complex values for setopt calls */
+ if(easysrc_data) {
+ fprintf(out, "\n");
+
+ for(ptr=easysrc_data; ptr; ptr = ptr->next)
+ fprintf(out, " %s\n", ptr->data);
+ }
+
+ fprintf(out, "\n");
+ for(ptr=easysrc_code; ptr; ptr = ptr->next) {
+ if(ptr->data[0]) {
+ fprintf(out, " %s\n", ptr->data);
+ }
+ else {
+ fprintf(out, "\n");
+ }
+ }
+
+ for(ptr=easysrc_clean; ptr; ptr = ptr->next)
+ fprintf(out, " %s\n", ptr->data);
+
+ for(i=0; ((c = srcend[i]) != NULL); i++)
+ fprintf(out, "%s\n", c);
+
+ if(fopened)
+ fclose(out);
+ }
+ }
+
+ easysrc_free();
+}
+
+#endif /* CURL_DISABLE_LIBCURL_OPTION */
diff --git a/src/tool_easysrc.h b/src/tool_easysrc.h
new file mode 100644
index 000000000..fa97cdcb3
--- /dev/null
+++ b/src/tool_easysrc.h
@@ -0,0 +1,47 @@
+#ifndef HEADER_CURL_TOOL_EASYSRC_H
+#define HEADER_CURL_TOOL_EASYSRC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+#ifndef CURL_DISABLE_LIBCURL_OPTION
+
+/* global variable declarations, for easy-interface source code generation */
+
+extern struct curl_slist *easysrc_decl; /* Variable declarations */
+extern struct curl_slist *easysrc_data; /* Build slists, forms etc. */
+extern struct curl_slist *easysrc_code; /* Setopt calls etc. */
+extern struct curl_slist *easysrc_toohard; /* Unconvertible setopt */
+extern struct curl_slist *easysrc_clean; /* Clean up (reverse order) */
+
+extern int easysrc_form_count; /* Number of curl_httppost variables */
+extern int easysrc_slist_count; /* Number of curl_slist variables */
+
+extern CURLcode easysrc_init(void);
+extern CURLcode easysrc_add(struct curl_slist **plist, const char *bupf);
+extern CURLcode easysrc_addf(struct curl_slist **plist, const char *fmt, ...);
+extern CURLcode easysrc_perform(void);
+extern CURLcode easysrc_cleanup(void);
+void dumpeasysrc(struct Configurable *config);
+
+#endif /* CURL_DISABLE_LIBCURL_OPTION */
+
+#endif /* HEADER_CURL_TOOL_EASYSRC_H */
diff --git a/src/tool_formparse.c b/src/tool_formparse.c
new file mode 100644
index 000000000..12b1a9d46
--- /dev/null
+++ b/src/tool_formparse.c
@@ -0,0 +1,307 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_mfiles.h"
+#include "tool_msgs.h"
+#include "tool_formparse.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/***************************************************************************
+ *
+ * formparse()
+ *
+ * Reads a 'name=value' parameter and builds the appropriate linked list.
+ *
+ * Specify files to upload with 'name=@filename'. Supports specified
+ * given Content-Type of the files. Such as ';type=<content-type>'.
+ *
+ * If literal_value is set, any initial '@' or '<' in the value string
+ * loses its special meaning, as does any embedded ';type='.
+ *
+ * You may specify more than one file for a single name (field). Specify
+ * multiple files by writing it like:
+ *
+ * 'name=@filename,filename2,filename3'
+ *
+ * If you want content-types specified for each too, write them like:
+ *
+ * 'name=@filename;type=image/gif,filename2,filename3'
+ *
+ * If you want custom headers added for a single part, write them in a separate
+ * file and do like this:
+ *
+ * 'name=foo;headers=@headerfile' or why not
+ * 'name=@filemame;headers=@headerfile'
+ *
+ * To upload a file, but to fake the file name that will be included in the
+ * formpost, do like this:
+ *
+ * 'name=@filename;filename=/dev/null'
+ *
+ * This function uses curl_formadd to fulfill it's job. Is heavily based on
+ * the old curl_formparse code.
+ *
+ ***************************************************************************/
+
+int formparse(struct Configurable *config,
+ const char *input,
+ struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ bool literal_value)
+{
+ /* nextarg MUST be a string in the format 'name=contents' and we'll
+ build a linked list with the info */
+ char name[256];
+ char *contents = NULL;
+ char type_major[128];
+ char type_minor[128];
+ char *contp;
+ const char *type = NULL;
+ char *sep;
+ char *sep2;
+
+ if((1 == sscanf(input, "%255[^=]=", name)) &&
+ ((contp = strchr(input, '=')) != NULL)) {
+ /* the input was using the correct format */
+
+ /* Allocate the contents */
+ contents = strdup(contp+1);
+ if(!contents) {
+ fprintf(config->errors, "out of memory\n");
+ return 1;
+ }
+ contp = contents;
+
+ if('@' == contp[0] && !literal_value) {
+
+ /* we use the @-letter to indicate file name(s) */
+
+ struct multi_files *multi_start = NULL;
+ struct multi_files *multi_current = NULL;
+
+ contp++;
+
+ do {
+ /* since this was a file, it may have a content-type specifier
+ at the end too, or a filename. Or both. */
+ char *ptr;
+ char *filename = NULL;
+
+ sep = strchr(contp, ';');
+ sep2 = strchr(contp, ',');
+
+ /* pick the closest */
+ if(sep2 && (sep2 < sep)) {
+ sep = sep2;
+
+ /* no type was specified! */
+ }
+
+ type = NULL;
+
+ if(sep) {
+ bool semicolon = (';' == *sep) ? TRUE : FALSE;
+
+ *sep = '\0'; /* terminate file name at separator */
+
+ ptr = sep+1; /* point to the text following the separator */
+
+ while(semicolon && ptr && (','!= *ptr)) {
+
+ /* pass all white spaces */
+ while(ISSPACE(*ptr))
+ ptr++;
+
+ if(checkprefix("type=", ptr)) {
+ /* set type pointer */
+ type = &ptr[5];
+
+ /* verify that this is a fine type specifier */
+ if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
+ type_major, type_minor)) {
+ warnf(config, "Illegally formatted content-type field!\n");
+ Curl_safefree(contents);
+ FreeMultiInfo(&multi_start, &multi_current);
+ return 2; /* illegal content-type syntax! */
+ }
+
+ /* now point beyond the content-type specifier */
+ sep = (char *)type + strlen(type_major)+strlen(type_minor)+1;
+
+ /* there's a semicolon following - we check if it is a filename
+ specified and if not we simply assume that it is text that
+ the user wants included in the type and include that too up
+ to the next zero or semicolon. */
+ if(*sep==';') {
+ if(!checkprefix(";filename=", sep)) {
+ sep2 = strchr(sep+1, ';');
+ if(sep2)
+ sep = sep2;
+ else
+ sep = sep + strlen(sep); /* point to end of string */
+ }
+ }
+ else
+ semicolon = FALSE;
+
+ if(*sep) {
+ *sep = '\0'; /* zero terminate type string */
+
+ ptr = sep+1;
+ }
+ else
+ ptr = NULL; /* end */
+ }
+ else if(checkprefix("filename=", ptr)) {
+ filename = &ptr[9];
+ ptr = strchr(filename, ';');
+ if(!ptr) {
+ ptr = strchr(filename, ',');
+ }
+ if(ptr) {
+ *ptr = '\0'; /* zero terminate */
+ ptr++;
+ }
+ }
+ else
+ /* confusion, bail out of loop */
+ break;
+ }
+
+ sep = ptr;
+ }
+
+ /* if type == NULL curl_formadd takes care of the problem */
+
+ if(!AddMultiFiles(contp, type, filename, &multi_start,
+ &multi_current)) {
+ warnf(config, "Error building form post!\n");
+ Curl_safefree(contents);
+ FreeMultiInfo(&multi_start, &multi_current);
+ return 3;
+ }
+ contp = sep; /* move the contents pointer to after the separator */
+
+ } while(sep && *sep); /* loop if there's another file name */
+
+ /* now we add the multiple files section */
+ if(multi_start) {
+ struct curl_forms *forms = NULL;
+ struct multi_files *ptr = multi_start;
+ unsigned int i, count = 0;
+ while(ptr) {
+ ptr = ptr->next;
+ ++count;
+ }
+ forms = malloc((count+1)*sizeof(struct curl_forms));
+ if(!forms) {
+ fprintf(config->errors, "Error building form post!\n");
+ Curl_safefree(contents);
+ FreeMultiInfo(&multi_start, &multi_current);
+ return 4;
+ }
+ for(i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next) {
+ forms[i].option = ptr->form.option;
+ forms[i].value = ptr->form.value;
+ }
+ forms[count].option = CURLFORM_END;
+ FreeMultiInfo(&multi_start, &multi_current);
+ if(curl_formadd(httppost, last_post,
+ CURLFORM_COPYNAME, name,
+ CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
+ warnf(config, "curl_formadd failed!\n");
+ Curl_safefree(forms);
+ Curl_safefree(contents);
+ return 5;
+ }
+ Curl_safefree(forms);
+ }
+ }
+ else {
+ struct curl_forms info[4];
+ int i = 0;
+ char *ct = literal_value ? NULL : strstr(contp, ";type=");
+
+ info[i].option = CURLFORM_COPYNAME;
+ info[i].value = name;
+ i++;
+
+ if(ct) {
+ info[i].option = CURLFORM_CONTENTTYPE;
+ info[i].value = &ct[6];
+ i++;
+ ct[0] = '\0'; /* zero terminate here */
+ }
+
+ if(contp[0]=='<' && !literal_value) {
+ info[i].option = CURLFORM_FILECONTENT;
+ info[i].value = contp+1;
+ i++;
+ info[i].option = CURLFORM_END;
+
+ if(curl_formadd(httppost, last_post,
+ CURLFORM_ARRAY, info, CURLFORM_END ) != 0) {
+ warnf(config, "curl_formadd failed, possibly the file %s is bad!\n",
+ contp+1);
+ Curl_safefree(contents);
+ return 6;
+ }
+ }
+ else {
+#ifdef CURL_DOES_CONVERSIONS
+ if(convert_to_network(contp, strlen(contp))) {
+ warnf(config, "curl_formadd failed!\n");
+ Curl_safefree(contents);
+ return 7;
+ }
+#endif
+ info[i].option = CURLFORM_COPYCONTENTS;
+ info[i].value = contp;
+ i++;
+ info[i].option = CURLFORM_END;
+ if(curl_formadd(httppost, last_post,
+ CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
+ warnf(config, "curl_formadd failed!\n");
+ Curl_safefree(contents);
+ return 8;
+ }
+ }
+ }
+
+ }
+ else {
+ warnf(config, "Illegally formatted input field!\n");
+ return 1;
+ }
+ Curl_safefree(contents);
+ return 0;
+}
+
diff --git a/src/tool_formparse.h b/src/tool_formparse.h
new file mode 100644
index 000000000..3cd915f6c
--- /dev/null
+++ b/src/tool_formparse.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_TOOL_FORMPARSE_H
+#define HEADER_CURL_TOOL_FORMPARSE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+int formparse(struct Configurable *config,
+ const char *input,
+ struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ bool literal_value);
+
+#endif /* HEADER_CURL_TOOL_FORMPARSE_H */
+
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
new file mode 100644
index 000000000..f3d72eeed
--- /dev/null
+++ b/src/tool_getparam.c
@@ -0,0 +1,1697 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#ifdef USE_MANUAL
+# include "hugehelp.h"
+#endif
+
+#include "tool_binmode.h"
+#include "tool_cfgable.h"
+#include "tool_cb_prg.h"
+#include "tool_formparse.h"
+#include "tool_getparam.h"
+#include "tool_help.h"
+#include "tool_helpers.h"
+#include "tool_libinfo.h"
+#include "tool_metalink.h"
+#include "tool_msgs.h"
+#include "tool_paramhlp.h"
+#include "tool_parsecfg.h"
+#include "tool_version.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef MSDOS
+# define USE_WATT32
+#endif
+
+#define GetStr(str,val) do { \
+ if(*(str)) { \
+ free(*(str)); \
+ *(str) = NULL; \
+ } \
+ if((val)) { \
+ *(str) = strdup((val)); \
+ if(!(*(str))) \
+ return PARAM_NO_MEM; \
+ } \
+} WHILE_FALSE
+
+struct LongShort {
+ const char *letter; /* short name option */
+ const char *lname; /* long name option */
+ bool extraparam; /* whether it takes an additional argument */
+};
+
+static const struct LongShort aliases[]= {
+ /* all these ones, starting with "*" or "$" as a short-option have *no*
+ short option to mention. */
+ {"*", "url", TRUE},
+ {"*a", "random-file", TRUE},
+ {"*b", "egd-file", TRUE},
+ {"*c", "connect-timeout", TRUE},
+ {"*d", "ciphers", TRUE},
+ {"*e", "disable-epsv", FALSE},
+ {"*E", "epsv", FALSE},
+ /* 'epsv' made like this to make --no-epsv and --epsv to work
+ although --disable-epsv is the documented option */
+#ifdef USE_ENVIRONMENT
+ {"*f", "environment", FALSE},
+#endif
+ {"*g", "trace", TRUE},
+ {"*h", "trace-ascii", TRUE},
+ {"*i", "limit-rate", TRUE},
+ {"*j", "compressed", FALSE},
+ {"*J", "tr-encoding", FALSE},
+ {"*k", "digest", FALSE},
+ {"*l", "negotiate", FALSE},
+ {"*m", "ntlm", FALSE},
+ {"*M", "ntlm-wb", FALSE},
+ {"*n", "basic", FALSE},
+ {"*o", "anyauth", FALSE},
+#ifdef USE_WATT32
+ {"*p", "wdebug", FALSE},
+#endif
+ {"*q", "ftp-create-dirs", FALSE},
+ {"*r", "create-dirs", FALSE},
+ {"*s", "max-redirs", TRUE},
+ {"*t", "proxy-ntlm", FALSE},
+ {"*u", "crlf", FALSE},
+ {"*v", "stderr", TRUE},
+ {"*w", "interface", TRUE},
+ {"*x", "krb" , TRUE},
+ {"*x", "krb4" , TRUE},
+ /* 'krb4' is the previous name */
+ {"*y", "max-filesize", TRUE},
+ {"*z", "disable-eprt", FALSE},
+ {"*Z", "eprt", FALSE},
+ /* 'eprt' made like this to make --no-eprt and --eprt to work
+ although --disable-eprt is the documented option */
+ {"$a", "ftp-ssl", FALSE},
+ /* 'ftp-ssl' deprecated name since 7.20.0 */
+ {"$a", "ssl", FALSE},
+ /* 'ssl' new option name in 7.20.0, previously this was ftp-ssl */
+ {"$b", "ftp-pasv", FALSE},
+ {"$c", "socks5", TRUE},
+ {"$c", "socks", TRUE},
+ /* 'socks' is how the option once was documented but we prefer
+ the --socks5 version for explicit version */
+ {"$d", "tcp-nodelay", FALSE},
+ {"$e", "proxy-digest", FALSE},
+ {"$f", "proxy-basic", FALSE},
+ {"$g", "retry", TRUE},
+ {"$h", "retry-delay", TRUE},
+ {"$i", "retry-max-time", TRUE},
+ {"$k", "proxy-negotiate", FALSE},
+ {"$m", "ftp-account", TRUE},
+ {"$n", "proxy-anyauth", FALSE},
+ {"$o", "trace-time", FALSE},
+ {"$p", "ignore-content-length", FALSE},
+ {"$q", "ftp-skip-pasv-ip", FALSE},
+ {"$r", "ftp-method", TRUE},
+ {"$s", "local-port", TRUE},
+ {"$t", "socks4", TRUE},
+ {"$T", "socks4a", TRUE},
+ {"$u", "ftp-alternative-to-user", TRUE},
+ {"$v", "ftp-ssl-reqd", FALSE},
+ /* 'ftp-ssl-reqd' deprecated name since 7.20.0 */
+ {"$v", "ssl-reqd", FALSE},
+ /* 'ssl-reqd' new in 7.20.0, previously this was ftp-ssl-reqd */
+ {"$w", "sessionid", FALSE},
+ /* ¡sessionid' listed as --no-sessionid in the help */
+ {"$x", "ftp-ssl-control", FALSE},
+ {"$y", "ftp-ssl-ccc", FALSE},
+ {"$j", "ftp-ssl-ccc-mode", TRUE},
+ {"$z", "libcurl", TRUE},
+ {"$#", "raw", FALSE},
+ {"$0", "post301", FALSE},
+ {"$1", "keepalive", FALSE},
+ /* 'keepalive' listed as --no-keepalive in the help */
+ {"$2", "socks5-hostname", TRUE},
+ {"$3", "keepalive-time", TRUE},
+ {"$4", "post302", FALSE},
+ {"$5", "noproxy", TRUE},
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ {"$6", "socks5-gssapi-service", TRUE},
+ {"$7", "socks5-gssapi-nec", FALSE},
+#endif
+ {"$8", "proxy1.0", TRUE},
+ {"$9", "tftp-blksize", TRUE},
+ {"$A", "mail-from", TRUE},
+ {"$B", "mail-rcpt", TRUE},
+ {"$C", "ftp-pret", FALSE},
+ {"$D", "proto", TRUE},
+ {"$E", "proto-redir", TRUE},
+ {"$F", "resolve", TRUE},
+ {"$G", "delegation", TRUE},
+ {"$H", "mail-auth", TRUE},
+ {"$I", "post303", FALSE},
+ {"$J", "metalink", FALSE},
+ {"0", "http1.0", FALSE},
+ {"1", "tlsv1", FALSE},
+ {"2", "sslv2", FALSE},
+ {"3", "sslv3", FALSE},
+ {"4", "ipv4", FALSE},
+ {"6", "ipv6", FALSE},
+ {"a", "append", FALSE},
+ {"A", "user-agent", TRUE},
+ {"b", "cookie", TRUE},
+ {"B", "use-ascii", FALSE},
+ {"c", "cookie-jar", TRUE},
+ {"C", "continue-at", TRUE},
+ {"d", "data", TRUE},
+ {"da", "data-ascii", TRUE},
+ {"db", "data-binary", TRUE},
+ {"de", "data-urlencode", TRUE},
+ {"D", "dump-header", TRUE},
+ {"e", "referer", TRUE},
+ {"E", "cert", TRUE},
+ {"Ea", "cacert", TRUE},
+ {"Eb", "cert-type", TRUE},
+ {"Ec", "key", TRUE},
+ {"Ed", "key-type", TRUE},
+ {"Ee", "pass", TRUE},
+ {"Ef", "engine", TRUE},
+ {"Eg", "capath ", TRUE},
+ {"Eh", "pubkey", TRUE},
+ {"Ei", "hostpubmd5", TRUE},
+ {"Ej", "crlfile", TRUE},
+ {"Ek", "tlsuser", TRUE},
+ {"El", "tlspassword", TRUE},
+ {"Em", "tlsauthtype", TRUE},
+ {"En", "ssl-allow-beast", FALSE},
+ {"f", "fail", FALSE},
+ {"F", "form", TRUE},
+ {"Fs", "form-string", TRUE},
+ {"g", "globoff", FALSE},
+ {"G", "get", FALSE},
+ {"h", "help", FALSE},
+ {"H", "header", TRUE},
+ {"i", "include", FALSE},
+ {"I", "head", FALSE},
+ {"j", "junk-session-cookies", FALSE},
+ {"J", "remote-header-name", FALSE},
+ {"k", "insecure", FALSE},
+ {"K", "config", TRUE},
+ {"l", "list-only", FALSE},
+ {"L", "location", FALSE},
+ {"Lt", "location-trusted", FALSE},
+ {"m", "max-time", TRUE},
+ {"M", "manual", FALSE},
+ {"n", "netrc", FALSE},
+ {"no", "netrc-optional", FALSE},
+ {"ne", "netrc-file", TRUE},
+ {"N", "buffer", FALSE},
+ /* 'buffer' listed as --no-buffer in the help */
+ {"o", "output", TRUE},
+ {"O", "remote-name", FALSE},
+ {"Oa", "remote-name-all", FALSE},
+ {"p", "proxytunnel", FALSE},
+ {"P", "ftpport", TRUE},
+ /* 'ftpport' old version */
+ {"P", "ftp-port", TRUE},
+ {"q", "disable", FALSE},
+ {"Q", "quote", TRUE},
+ {"r", "range", TRUE},
+ {"R", "remote-time", FALSE},
+ {"s", "silent", FALSE},
+ {"S", "show-error", FALSE},
+ {"t", "telnet-options", TRUE},
+ /* 'telnet-options' documented as telnet-option */
+ {"T", "upload-file", TRUE},
+ {"u", "user", TRUE},
+ {"U", "proxy-user", TRUE},
+ {"v", "verbose", FALSE},
+ {"V", "version", FALSE},
+ {"w", "write-out", TRUE},
+ {"x", "proxy", TRUE},
+ {"X", "request", TRUE},
+ {"X", "http-request", TRUE},
+ /* 'http-request' OBSOLETE VERSION */
+ {"Y", "speed-limit", TRUE},
+ {"y", "speed-time", TRUE},
+ {"z", "time-cond", TRUE},
+ {"#", "progress-bar", FALSE},
+ {"~", "xattr", FALSE},
+};
+
+struct feat {
+ const char *name;
+ int bitmask;
+};
+
+static const struct feat feats[] = {
+ {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
+ {"Debug", CURL_VERSION_DEBUG},
+ {"TrackMemory", CURL_VERSION_CURLDEBUG},
+ {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
+ {"IDN", CURL_VERSION_IDN},
+ {"IPv6", CURL_VERSION_IPV6},
+ {"Largefile", CURL_VERSION_LARGEFILE},
+ {"NTLM", CURL_VERSION_NTLM},
+ {"NTLM_WB", CURL_VERSION_NTLM_WB},
+ {"SPNEGO", CURL_VERSION_SPNEGO},
+ {"SSL", CURL_VERSION_SSL},
+ {"SSPI", CURL_VERSION_SSPI},
+ {"krb4", CURL_VERSION_KERBEROS4},
+ {"libz", CURL_VERSION_LIBZ},
+ {"CharConv", CURL_VERSION_CONV},
+ {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP}
+};
+
+ParameterError getparameter(char *flag, /* f or -long-flag */
+ char *nextarg, /* NULL if unset */
+ bool *usedarg, /* set to TRUE if the arg
+ has been used */
+ struct Configurable *config)
+{
+ char letter;
+ char subletter = '\0'; /* subletters can only occur on long options */
+ int rc;
+ const char *parse = NULL;
+ unsigned int j;
+ time_t now;
+ int hit = -1;
+ bool longopt = FALSE;
+ bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */
+ ParameterError err;
+ bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled
+ by using --OPTION or --no-OPTION */
+
+
+ if(('-' != flag[0]) ||
+ (('-' == flag[0]) && ('-' == flag[1]))) {
+ /* this should be a long name */
+ char *word = ('-' == flag[0]) ? flag+2 : flag;
+ size_t fnam = strlen(word);
+ int numhits = 0;
+
+ if(!strncmp(word, "no-", 3)) {
+ /* disable this option but ignore the "no-" part when looking for it */
+ word += 3;
+ toggle = FALSE;
+ }
+
+ for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
+ if(curlx_strnequal(aliases[j].lname, word, fnam)) {
+ longopt = TRUE;
+ numhits++;
+ if(curlx_raw_equal(aliases[j].lname, word)) {
+ parse = aliases[j].letter;
+ hit = j;
+ numhits = 1; /* a single unique hit */
+ break;
+ }
+ parse = aliases[j].letter;
+ hit = j;
+ }
+ }
+ if(numhits > 1) {
+ /* this is at least the second match! */
+ return PARAM_OPTION_AMBIGUOUS;
+ }
+ if(hit < 0) {
+ return PARAM_OPTION_UNKNOWN;
+ }
+ }
+ else {
+ flag++; /* prefixed with one dash, pass it */
+ hit = -1;
+ parse = flag;
+ }
+
+ do {
+ /* we can loop here if we have multiple single-letters */
+
+ if(!longopt) {
+ if(NULL != parse) {
+ letter = (char)*parse;
+ }
+ else {
+ letter = '\0';
+ }
+ subletter='\0';
+ }
+ else {
+ letter = parse[0];
+ subletter = parse[1];
+ }
+ *usedarg = FALSE; /* default is that we don't use the arg */
+
+ if(hit < 0) {
+ for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
+ if(letter == aliases[j].letter[0]) {
+ hit = j;
+ break;
+ }
+ }
+ if(hit < 0) {
+ return PARAM_OPTION_UNKNOWN;
+ }
+ }
+
+ if(aliases[hit].extraparam) {
+ /* this option requires an extra parameter */
+ if(!longopt && parse[1]) {
+ nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
+ singleopt = TRUE; /* don't loop anymore after this */
+ }
+ else if(!nextarg)
+ return PARAM_REQUIRES_PARAMETER;
+ else
+ *usedarg = TRUE; /* mark it as used */
+ }
+
+ switch(letter) {
+ case '*': /* options without a short option */
+ switch(subletter) {
+ case 'a': /* random-file */
+ GetStr(&config->random_file, nextarg);
+ break;
+ case 'b': /* egd-file */
+ GetStr(&config->egd_file, nextarg);
+ break;
+ case 'c': /* connect-timeout */
+ err = str2unum(&config->connecttimeout, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'd': /* ciphers */
+ GetStr(&config->cipher_list, nextarg);
+ break;
+ case 'e': /* --disable-epsv */
+ config->disable_epsv = toggle;
+ break;
+ case 'E': /* --epsv */
+ config->disable_epsv = (!toggle)?TRUE:FALSE;
+ break;
+#ifdef USE_ENVIRONMENT
+ case 'f':
+ config->writeenv = toggle;
+ break;
+#endif
+ case 'g': /* --trace */
+ GetStr(&config->trace_dump, nextarg);
+ if(config->tracetype && (config->tracetype != TRACE_BIN))
+ warnf(config, "--trace overrides an earlier trace/verbose option\n");
+ config->tracetype = TRACE_BIN;
+ break;
+ case 'h': /* --trace-ascii */
+ GetStr(&config->trace_dump, nextarg);
+ if(config->tracetype && (config->tracetype != TRACE_ASCII))
+ warnf(config,
+ "--trace-ascii overrides an earlier trace/verbose option\n");
+ config->tracetype = TRACE_ASCII;
+ break;
+ case 'i': /* --limit-rate */
+ {
+ /* We support G, M, K too */
+ char *unit;
+ curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
+
+ if(!*unit)
+ unit = (char *)"b";
+ else if(strlen(unit) > 1)
+ unit = (char *)"w"; /* unsupported */
+
+ switch(*unit) {
+ case 'G':
+ case 'g':
+ value *= 1024*1024*1024;
+ break;
+ case 'M':
+ case 'm':
+ value *= 1024*1024;
+ break;
+ case 'K':
+ case 'k':
+ value *= 1024;
+ break;
+ case 'b':
+ case 'B':
+ /* for plain bytes, leave as-is */
+ break;
+ default:
+ warnf(config, "unsupported rate unit. Use G, M, K or B!\n");
+ return PARAM_BAD_USE;
+ }
+ config->recvpersecond = value;
+ config->sendpersecond = value;
+ }
+ break;
+
+ case 'j': /* --compressed */
+ if(toggle && !(curlinfo->features & CURL_VERSION_LIBZ))
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ config->encoding = toggle;
+ break;
+
+ case 'J': /* --tr-encoding */
+ config->tr_encoding = toggle;
+ break;
+
+ case 'k': /* --digest */
+ if(toggle)
+ config->authtype |= CURLAUTH_DIGEST;
+ else
+ config->authtype &= ~CURLAUTH_DIGEST;
+ break;
+
+ case 'l': /* --negotiate */
+ if(toggle) {
+ if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
+ config->authtype |= CURLAUTH_GSSNEGOTIATE;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ }
+ else
+ config->authtype &= ~CURLAUTH_GSSNEGOTIATE;
+ break;
+
+ case 'm': /* --ntlm */
+ if(toggle) {
+ if(curlinfo->features & CURL_VERSION_NTLM)
+ config->authtype |= CURLAUTH_NTLM;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ }
+ else
+ config->authtype &= ~CURLAUTH_NTLM;
+ break;
+
+ case 'M': /* --ntlm-wb */
+ if(toggle) {
+ if(curlinfo->features & CURL_VERSION_NTLM_WB)
+ config->authtype |= CURLAUTH_NTLM_WB;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ }
+ else
+ config->authtype &= ~CURLAUTH_NTLM_WB;
+ break;
+
+ case 'n': /* --basic for completeness */
+ if(toggle)
+ config->authtype |= CURLAUTH_BASIC;
+ else
+ config->authtype &= ~CURLAUTH_BASIC;
+ break;
+
+ case 'o': /* --anyauth, let libcurl pick it */
+ if(toggle)
+ config->authtype = CURLAUTH_ANY;
+ /* --no-anyauth simply doesn't touch it */
+ break;
+
+#ifdef USE_WATT32
+ case 'p': /* --wdebug */
+ dbug_init();
+ break;
+#endif
+ case 'q': /* --ftp-create-dirs */
+ config->ftp_create_dirs = toggle;
+ break;
+
+ case 'r': /* --create-dirs */
+ config->create_dirs = TRUE;
+ break;
+
+ case 's': /* --max-redirs */
+ /* specified max no of redirects (http(s)), this accepts -1 as a
+ special condition */
+ err = str2num(&config->maxredirs, nextarg);
+ if(err)
+ return err;
+ if(config->maxredirs < -1)
+ return PARAM_BAD_NUMERIC;
+ break;
+
+ case 't': /* --proxy-ntlm */
+ if(curlinfo->features & CURL_VERSION_NTLM)
+ config->proxyntlm = toggle;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+
+ case 'u': /* --crlf */
+ /* LF -> CRLF conversion? */
+ config->crlf = TRUE;
+ break;
+
+ case 'v': /* --stderr */
+ if(strcmp(nextarg, "-")) {
+ FILE *newfile = fopen(nextarg, "wt");
+ if(!newfile)
+ warnf(config, "Failed to open %s!\n", nextarg);
+ else {
+ if(config->errors_fopened)
+ fclose(config->errors);
+ config->errors = newfile;
+ config->errors_fopened = TRUE;
+ }
+ }
+ else
+ config->errors = stdout;
+ break;
+ case 'w': /* --interface */
+ /* interface */
+ GetStr(&config->iface, nextarg);
+ break;
+ case 'x': /* --krb */
+ /* kerberos level string */
+ if(curlinfo->features & (CURL_VERSION_KERBEROS4 |
+ CURL_VERSION_GSSNEGOTIATE))
+ GetStr(&config->krblevel, nextarg);
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'y': /* --max-filesize */
+ err = str2offset(&config->max_filesize, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'z': /* --disable-eprt */
+ config->disable_eprt = toggle;
+ break;
+ case 'Z': /* --eprt */
+ config->disable_eprt = (!toggle)?TRUE:FALSE;
+ break;
+
+ default: /* the URL! */
+ {
+ struct getout *url;
+ if(config->url_get || ((config->url_get = config->url_list) != NULL)) {
+ /* there's a node here, if it already is filled-in continue to find
+ an "empty" node */
+ while(config->url_get && (config->url_get->flags & GETOUT_URL))
+ config->url_get = config->url_get->next;
+ }
+
+ /* now there might or might not be an available node to fill in! */
+
+ if(config->url_get)
+ /* existing node */
+ url = config->url_get;
+ else
+ /* there was no free node, create one! */
+ url = new_getout(config);
+
+ if(!url)
+ return PARAM_NO_MEM;
+ else {
+ /* fill in the URL */
+ GetStr(&url->url, nextarg);
+ url->flags |= GETOUT_URL;
+ }
+ }
+ }
+ break;
+ case '$': /* more options without a short option */
+ switch(subletter) {
+ case 'a': /* --ftp-ssl */
+ if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ config->ftp_ssl = toggle;
+ break;
+ case 'b': /* --ftp-pasv */
+ Curl_safefree(config->ftpport);
+ break;
+ case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
+ the name locally and passes on the resolved address */
+ GetStr(&config->socksproxy, nextarg);
+ config->socksver = CURLPROXY_SOCKS5;
+ break;
+ case 't': /* --socks4 specifies a socks4 proxy to use */
+ GetStr(&config->socksproxy, nextarg);
+ config->socksver = CURLPROXY_SOCKS4;
+ break;
+ case 'T': /* --socks4a specifies a socks4a proxy to use */
+ GetStr(&config->socksproxy, nextarg);
+ config->socksver = CURLPROXY_SOCKS4A;
+ break;
+ case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
+ resolving with the proxy */
+ GetStr(&config->socksproxy, nextarg);
+ config->socksver = CURLPROXY_SOCKS5_HOSTNAME;
+ break;
+ case 'd': /* --tcp-nodelay option */
+ config->tcp_nodelay = toggle;
+ break;
+ case 'e': /* --proxy-digest */
+ config->proxydigest = toggle;
+ break;
+ case 'f': /* --proxy-basic */
+ config->proxybasic = toggle;
+ break;
+ case 'g': /* --retry */
+ err = str2unum(&config->req_retry, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'h': /* --retry-delay */
+ err = str2unum(&config->retry_delay, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'i': /* --retry-max-time */
+ err = str2unum(&config->retry_maxtime, nextarg);
+ if(err)
+ return err;
+ break;
+
+ case 'k': /* --proxy-negotiate */
+ if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
+ config->proxynegotiate = toggle;
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'm': /* --ftp-account */
+ GetStr(&config->ftp_account, nextarg);
+ break;
+ case 'n': /* --proxy-anyauth */
+ config->proxyanyauth = toggle;
+ break;
+ case 'o': /* --trace-time */
+ config->tracetime = toggle;
+ break;
+ case 'p': /* --ignore-content-length */
+ config->ignorecl = toggle;
+ break;
+ case 'q': /* --ftp-skip-pasv-ip */
+ config->ftp_skip_ip = toggle;
+ break;
+ case 'r': /* --ftp-method (undocumented at this point) */
+ config->ftp_filemethod = ftpfilemethod(config, nextarg);
+ break;
+ case 's': /* --local-port */
+ rc = sscanf(nextarg, "%d - %d",
+ &config->localport,
+ &config->localportrange);
+ if(!rc)
+ return PARAM_BAD_USE;
+ else if(rc == 1)
+ config->localportrange = 1; /* default number of ports to try */
+ else {
+ config->localportrange -= config->localport;
+ if(config->localportrange < 1) {
+ warnf(config, "bad range input\n");
+ return PARAM_BAD_USE;
+ }
+ }
+ break;
+ case 'u': /* --ftp-alternative-to-user */
+ GetStr(&config->ftp_alternative_to_user, nextarg);
+ break;
+ case 'v': /* --ftp-ssl-reqd */
+ if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ config->ftp_ssl_reqd = toggle;
+ break;
+ case 'w': /* --no-sessionid */
+ config->disable_sessionid = (!toggle)?TRUE:FALSE;
+ break;
+ case 'x': /* --ftp-ssl-control */
+ if(toggle && !(curlinfo->features & CURL_VERSION_SSL))
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ config->ftp_ssl_control = toggle;
+ break;
+ case 'y': /* --ftp-ssl-ccc */
+ config->ftp_ssl_ccc = toggle;
+ if(!config->ftp_ssl_ccc_mode)
+ config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
+ break;
+ case 'j': /* --ftp-ssl-ccc-mode */
+ config->ftp_ssl_ccc = TRUE;
+ config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
+ break;
+ case 'z': /* --libcurl */
+#ifdef CURL_DISABLE_LIBCURL_OPTION
+ warnf(config,
+ "--libcurl option was disabled at build-time!\n");
+ return PARAM_OPTION_UNKNOWN;
+#else
+ GetStr(&config->libcurl, nextarg);
+ break;
+#endif
+ case '#': /* --raw */
+ config->raw = toggle;
+ break;
+ case '0': /* --post301 */
+ config->post301 = toggle;
+ break;
+ case '1': /* --no-keepalive */
+ config->nokeepalive = (!toggle)?TRUE:FALSE;
+ break;
+ case '3': /* --keepalive-time */
+ err = str2unum(&config->alivetime, nextarg);
+ if(err)
+ return err;
+ break;
+ case '4': /* --post302 */
+ config->post302 = toggle;
+ break;
+ case 'I': /* --post303 */
+ config->post303 = toggle;
+ break;
+ case '5': /* --noproxy */
+ /* This specifies the noproxy list */
+ GetStr(&config->noproxy, nextarg);
+ break;
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ case '6': /* --socks5-gssapi-service */
+ GetStr(&config->socks5_gssapi_service, nextarg);
+ break;
+ case '7': /* --socks5-gssapi-nec*/
+ config->socks5_gssapi_nec = TRUE;
+ break;
+#endif
+ case '8': /* --proxy1.0 */
+ /* http 1.0 proxy */
+ GetStr(&config->proxy, nextarg);
+ config->proxyver = CURLPROXY_HTTP_1_0;
+ break;
+ case '9': /* --tftp-blksize */
+ err = str2unum(&config->tftp_blksize, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'A': /* --mail-from */
+ GetStr(&config->mail_from, nextarg);
+ break;
+ case 'B': /* --mail-rcpt */
+ /* append receiver to a list */
+ err = add2list(&config->mail_rcpt, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'C': /* --ftp-pret */
+ config->ftp_pret = toggle;
+ break;
+ case 'D': /* --proto */
+ config->proto_present = TRUE;
+ if(proto2num(config, &config->proto, nextarg))
+ return PARAM_BAD_USE;
+ break;
+ case 'E': /* --proto-redir */
+ config->proto_redir_present = TRUE;
+ if(proto2num(config, &config->proto_redir, nextarg))
+ return PARAM_BAD_USE;
+ break;
+ case 'F': /* --resolve */
+ err = add2list(&config->resolve, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'G': /* --delegation LEVEL */
+ config->gssapi_delegation = delegation(config, nextarg);
+ break;
+ case 'H': /* --mail-auth */
+ GetStr(&config->mail_auth, nextarg);
+ break;
+ case 'J': /* --metalink */
+ {
+#ifdef USE_METALINK
+ int mlmaj, mlmin, mlpatch;
+ metalink_get_version(&mlmaj, &mlmin, &mlpatch);
+ if((mlmaj*10000)+(mlmin*100)+mlpatch < CURL_REQ_LIBMETALINK_VERS) {
+ warnf(config,
+ "--metalink option cannot be used because the version of "
+ "the linked libmetalink library is too old. "
+ "Required: %d.%d.%d, found %d.%d.%d\n",
+ CURL_REQ_LIBMETALINK_MAJOR,
+ CURL_REQ_LIBMETALINK_MINOR,
+ CURL_REQ_LIBMETALINK_PATCH,
+ mlmaj, mlmin, mlpatch);
+ return PARAM_BAD_USE;
+ }
+ else
+ config->use_metalink = toggle;
+#else
+ warnf(config, "--metalink option is ignored because the binary is "
+ "built without the Metalink support.\n");
+#endif
+ break;
+ }
+ }
+ break;
+ case '#': /* --progress-bar */
+ if(toggle)
+ config->progressmode = CURL_PROGRESS_BAR;
+ else
+ config->progressmode = CURL_PROGRESS_STATS;
+ break;
+ case '~': /* --xattr */
+ config->xattr = toggle;
+ break;
+ case '0':
+ /* HTTP version 1.0 */
+ config->httpversion = CURL_HTTP_VERSION_1_0;
+ break;
+ case '1':
+ /* TLS version 1 */
+ config->ssl_version = CURL_SSLVERSION_TLSv1;
+ break;
+ case '2':
+ /* SSL version 2 */
+ config->ssl_version = CURL_SSLVERSION_SSLv2;
+ break;
+ case '3':
+ /* SSL version 3 */
+ config->ssl_version = CURL_SSLVERSION_SSLv3;
+ break;
+ case '4':
+ /* IPv4 */
+ config->ip_version = 4;
+ break;
+ case '6':
+ /* IPv6 */
+ config->ip_version = 6;
+ break;
+ case 'a':
+ /* This makes the FTP sessions use APPE instead of STOR */
+ config->ftp_append = toggle;
+ break;
+ case 'A':
+ /* This specifies the User-Agent name */
+ GetStr(&config->useragent, nextarg);
+ break;
+ case 'b': /* cookie string coming up: */
+ if(nextarg[0] == '@') {
+ nextarg++;
+ }
+ else if(strchr(nextarg, '=')) {
+ /* A cookie string must have a =-letter */
+ GetStr(&config->cookie, nextarg);
+ break;
+ }
+ /* We have a cookie file to read from! */
+ GetStr(&config->cookiefile, nextarg);
+ break;
+ case 'B':
+ /* use ASCII/text when transferring */
+ config->use_ascii = toggle;
+ break;
+ case 'c':
+ /* get the file name to dump all cookies in */
+ GetStr(&config->cookiejar, nextarg);
+ break;
+ case 'C':
+ /* This makes us continue an ftp transfer at given position */
+ if(!curlx_strequal(nextarg, "-")) {
+ err = str2offset(&config->resume_from, nextarg);
+ if(err)
+ return err;
+ config->resume_from_current = FALSE;
+ }
+ else {
+ config->resume_from_current = TRUE;
+ config->resume_from = 0;
+ }
+ config->use_resume=TRUE;
+ break;
+ case 'd':
+ /* postfield data */
+ {
+ char *postdata = NULL;
+ FILE *file;
+ size_t size = 0;
+
+ if(subletter == 'e') { /* --data-urlencode*/
+ /* [name]=[content], we encode the content part only
+ * [name]@[file name]
+ *
+ * Case 2: we first load the file using that name and then encode
+ * the content.
+ */
+ const char *p = strchr(nextarg, '=');
+ size_t nlen;
+ char is_file;
+ if(!p)
+ /* there was no '=' letter, check for a '@' instead */
+ p = strchr(nextarg, '@');
+ if(p) {
+ nlen = p - nextarg; /* length of the name part */
+ is_file = *p++; /* pass the separator */
+ }
+ else {
+ /* neither @ nor =, so no name and it isn't a file */
+ nlen = is_file = 0;
+ p = nextarg;
+ }
+ if('@' == is_file) {
+ /* a '@' letter, it means that a file name or - (stdin) follows */
+
+ if(curlx_strequal("-", p)) {
+ file = stdin;
+ set_binmode(stdin);
+ }
+ else {
+ file = fopen(p, "rb");
+ if(!file)
+ warnf(config,
+ "Couldn't read data from file \"%s\", this makes "
+ "an empty POST.\n", nextarg);
+ }
+
+ err = file2memory(&postdata, &size, file);
+
+ if(file && (file != stdin))
+ fclose(file);
+ if(err)
+ return err;
+ }
+ else {
+ GetStr(&postdata, p);
+ if(postdata)
+ size = strlen(postdata);
+ }
+
+ if(!postdata) {
+ /* no data from the file, point to a zero byte string to make this
+ get sent as a POST anyway */
+ postdata = strdup("");
+ if(!postdata)
+ return PARAM_NO_MEM;
+ size = 0;
+ }
+ else {
+ char *enc = curl_easy_escape(config->easy, postdata, (int)size);
+ Curl_safefree(postdata); /* no matter if it worked or not */
+ if(enc) {
+ /* now make a string with the name from above and append the
+ encoded string */
+ size_t outlen = nlen + strlen(enc) + 2;
+ char *n = malloc(outlen);
+ if(!n) {
+ curl_free(enc);
+ return PARAM_NO_MEM;
+ }
+ if(nlen > 0) { /* only append '=' if we have a name */
+ snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc);
+ size = outlen-1;
+ }
+ else {
+ strcpy(n, enc);
+ size = outlen-2; /* since no '=' was inserted */
+ }
+ curl_free(enc);
+ postdata = n;
+ }
+ else
+ return PARAM_NO_MEM;
+ }
+ }
+ else if('@' == *nextarg) {
+ /* the data begins with a '@' letter, it means that a file name
+ or - (stdin) follows */
+ nextarg++; /* pass the @ */
+
+ if(curlx_strequal("-", nextarg)) {
+ file = stdin;
+ if(subletter == 'b') /* forced data-binary */
+ set_binmode(stdin);
+ }
+ else {
+ file = fopen(nextarg, "rb");
+ if(!file)
+ warnf(config, "Couldn't read data from file \"%s\", this makes "
+ "an empty POST.\n", nextarg);
+ }
+
+ if(subletter == 'b')
+ /* forced binary */
+ err = file2memory(&postdata, &size, file);
+ else {
+ err = file2string(&postdata, file);
+ if(postdata)
+ size = strlen(postdata);
+ }
+
+ if(file && (file != stdin))
+ fclose(file);
+ if(err)
+ return err;
+
+ if(!postdata) {
+ /* no data from the file, point to a zero byte string to make this
+ get sent as a POST anyway */
+ postdata = strdup("");
+ if(!postdata)
+ return PARAM_NO_MEM;
+ }
+ }
+ else {
+ GetStr(&postdata, nextarg);
+ if(postdata)
+ size = strlen(postdata);
+ }
+
+#ifdef CURL_DOES_CONVERSIONS
+ if(subletter != 'b') {
+ /* NOT forced binary, convert to ASCII */
+ if(convert_to_network(postdata, strlen(postdata))) {
+ Curl_safefree(postdata);
+ return PARAM_NO_MEM;
+ }
+ }
+#endif
+
+ if(config->postfields) {
+ /* we already have a string, we append this one with a separating
+ &-letter */
+ char *oldpost = config->postfields;
+ curl_off_t oldlen = config->postfieldsize;
+ curl_off_t newlen = oldlen + size + 2;
+ config->postfields = malloc((size_t)newlen);
+ if(!config->postfields) {
+ Curl_safefree(oldpost);
+ Curl_safefree(postdata);
+ return PARAM_NO_MEM;
+ }
+ memcpy(config->postfields, oldpost, (size_t)oldlen);
+ /* use byte value 0x26 for '&' to accommodate non-ASCII platforms */
+ config->postfields[oldlen] = '\x26';
+ memcpy(&config->postfields[oldlen+1], postdata, size);
+ config->postfields[oldlen+1+size] = '\0';
+ Curl_safefree(oldpost);
+ Curl_safefree(postdata);
+ config->postfieldsize += size+1;
+ }
+ else {
+ config->postfields = postdata;
+ config->postfieldsize = size;
+ }
+ }
+ /*
+ We can't set the request type here, as this data might be used in
+ a simple GET if -G is used. Already or soon.
+
+ if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) {
+ Curl_safefree(postdata);
+ return PARAM_BAD_USE;
+ }
+ */
+ break;
+ case 'D':
+ /* dump-header to given file name */
+ GetStr(&config->headerfile, nextarg);
+ break;
+ case 'e':
+ {
+ char *ptr = strstr(nextarg, ";auto");
+ if(ptr) {
+ /* Automatic referer requested, this may be combined with a
+ set initial one */
+ config->autoreferer = TRUE;
+ *ptr = 0; /* zero terminate here */
+ }
+ else
+ config->autoreferer = FALSE;
+ GetStr(&config->referer, nextarg);
+ }
+ break;
+ case 'E':
+ switch(subletter) {
+ case 'a': /* CA info PEM file */
+ /* CA info PEM file */
+ GetStr(&config->cacert, nextarg);
+ break;
+ case 'b': /* cert file type */
+ GetStr(&config->cert_type, nextarg);
+ break;
+ case 'c': /* private key file */
+ GetStr(&config->key, nextarg);
+ break;
+ case 'd': /* private key file type */
+ GetStr(&config->key_type, nextarg);
+ break;
+ case 'e': /* private key passphrase */
+ GetStr(&config->key_passwd, nextarg);
+ cleanarg(nextarg);
+ break;
+ case 'f': /* crypto engine */
+ GetStr(&config->engine, nextarg);
+ if(config->engine && curlx_raw_equal(config->engine,"list"))
+ config->list_engines = TRUE;
+ break;
+ case 'g': /* CA info PEM file */
+ /* CA cert directory */
+ GetStr(&config->capath, nextarg);
+ break;
+ case 'h': /* --pubkey public key file */
+ GetStr(&config->pubkey, nextarg);
+ break;
+ case 'i': /* --hostpubmd5 md5 of the host public key */
+ GetStr(&config->hostpubmd5, nextarg);
+ if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
+ return PARAM_BAD_USE;
+ break;
+ case 'j': /* CRL info PEM file */
+ /* CRL file */
+ GetStr(&config->crlfile, nextarg);
+ break;
+ case 'k': /* TLS username */
+ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
+ GetStr(&config->tls_username, nextarg);
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'l': /* TLS password */
+ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP)
+ GetStr(&config->tls_password, nextarg);
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'm': /* TLS authentication type */
+ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
+ GetStr(&config->tls_authtype, nextarg);
+ if(!strequal(config->tls_authtype, "SRP"))
+ return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
+ }
+ else
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ case 'n': /* no empty SSL fragments */
+ if(curlinfo->features & CURL_VERSION_SSL)
+ config->ssl_allow_beast = toggle;
+ break;
+ default: /* certificate file */
+ {
+ char *ptr = strchr(nextarg, ':');
+ /* Since we live in a world of weirdness and confusion, the win32
+ dudes can use : when using drive letters and thus
+ c:\file:password needs to work. In order not to break
+ compatibility, we still use : as separator, but we try to detect
+ when it is used for a file name! On windows. */
+#ifdef WIN32
+ if(ptr &&
+ (ptr == &nextarg[1]) &&
+ (nextarg[2] == '\\' || nextarg[2] == '/') &&
+ (ISALPHA(nextarg[0])) )
+ /* colon in the second column, followed by a backslash, and the
+ first character is an alphabetic letter:
+
+ this is a drive letter colon */
+ ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
+#endif
+ if(ptr) {
+ /* we have a password too */
+ *ptr = '\0';
+ ptr++;
+ GetStr(&config->key_passwd, ptr);
+ }
+ GetStr(&config->cert, nextarg);
+ cleanarg(nextarg);
+ }
+ }
+ break;
+ case 'f':
+ /* fail hard on errors */
+ config->failonerror = toggle;
+ break;
+ case 'F':
+ /* "form data" simulation, this is a little advanced so lets do our best
+ to sort this out slowly and carefully */
+ if(formparse(config,
+ nextarg,
+ &config->httppost,
+ &config->last_post,
+ (subletter=='s')?TRUE:FALSE)) /* 's' means literal string */
+ return PARAM_BAD_USE;
+ if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq))
+ return PARAM_BAD_USE;
+ break;
+
+ case 'g': /* g disables URLglobbing */
+ config->globoff = toggle;
+ break;
+
+ case 'G': /* HTTP GET */
+ config->use_httpget = TRUE;
+ break;
+
+ case 'h': /* h for help */
+ if(toggle) {
+ tool_help();
+ return PARAM_HELP_REQUESTED;
+ }
+ /* we now actually support --no-help too! */
+ break;
+ case 'H':
+ /* A custom header to append to a list */
+ err = add2list(&config->headers, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'i':
+ config->include_headers = toggle; /* include the headers as well in the
+ general output stream */
+ break;
+ case 'j':
+ config->cookiesession = toggle;
+ break;
+ case 'I':
+ /*
+ * no_body will imply include_headers later on
+ */
+ config->no_body = toggle;
+ if(SetHTTPrequest(config,
+ (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
+ &config->httpreq))
+ return PARAM_BAD_USE;
+ break;
+ case 'J': /* --remote-header-name */
+ if(config->include_headers) {
+ warnf(config,
+ "--include and --remote-header-name cannot be combined.\n");
+ return PARAM_BAD_USE;
+ }
+ config->content_disposition = toggle;
+ break;
+ case 'k': /* allow insecure SSL connects */
+ config->insecure_ok = toggle;
+ break;
+ case 'K': /* parse config file */
+ if(parseconfig(nextarg, config))
+ warnf(config, "error trying read config from the '%s' file\n",
+ nextarg);
+ break;
+ case 'l':
+ config->dirlistonly = toggle; /* only list the names of the FTP dir */
+ break;
+ case 'L':
+ config->followlocation = toggle; /* Follow Location: HTTP headers */
+ switch (subletter) {
+ case 't':
+ /* Continue to send authentication (user+password) when following
+ * locations, even when hostname changed */
+ config->unrestricted_auth = toggle;
+ break;
+ }
+ break;
+ case 'm':
+ /* specified max time */
+ err = str2unum(&config->timeout, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'M': /* M for manual, huge help */
+ if(toggle) { /* --no-manual shows no manual... */
+#ifdef USE_MANUAL
+ hugehelp();
+ return PARAM_HELP_REQUESTED;
+#else
+ warnf(config,
+ "built-in manual was disabled at build-time!\n");
+ return PARAM_OPTION_UNKNOWN;
+#endif
+ }
+ break;
+ case 'n':
+ switch(subletter) {
+ case 'o': /* CA info PEM file */
+ /* use .netrc or URL */
+ config->netrc_opt = toggle;
+ break;
+ case 'e': /* netrc-file */
+ GetStr(&config->netrc_file, nextarg);
+ break;
+ default:
+ /* pick info from .netrc, if this is used for http, curl will
+ automatically enfore user+password with the request */
+ config->netrc = toggle;
+ break;
+ }
+ break;
+ case 'N':
+ /* disable the output I/O buffering. note that the option is called
+ --buffer but is mostly used in the negative form: --no-buffer */
+ if(longopt)
+ config->nobuffer = (!toggle)?TRUE:FALSE;
+ else
+ config->nobuffer = toggle;
+ break;
+ case 'O': /* --remote-name */
+ if(subletter == 'a') { /* --remote-name-all */
+ config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
+ break;
+ }
+ /* fall-through! */
+ case 'o': /* --output */
+ /* output file */
+ {
+ struct getout *url;
+ if(config->url_out || ((config->url_out = config->url_list) != NULL)) {
+ /* there's a node here, if it already is filled-in continue to find
+ an "empty" node */
+ while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE))
+ config->url_out = config->url_out->next;
+ }
+
+ /* now there might or might not be an available node to fill in! */
+
+ if(config->url_out)
+ /* existing node */
+ url = config->url_out;
+ else
+ /* there was no free node, create one! */
+ url = new_getout(config);
+
+ if(!url)
+ return PARAM_NO_MEM;
+ else {
+ /* fill in the outfile */
+ if('o' == letter) {
+ GetStr(&url->outfile, nextarg);
+ url->flags &= ~GETOUT_USEREMOTE; /* switch off */
+ }
+ else {
+ url->outfile = NULL; /* leave it */
+ if(toggle)
+ url->flags |= GETOUT_USEREMOTE; /* switch on */
+ else
+ url->flags &= ~GETOUT_USEREMOTE; /* switch off */
+ }
+ url->flags |= GETOUT_OUTFILE;
+ }
+ }
+ break;
+ case 'P':
+ /* This makes the FTP sessions use PORT instead of PASV */
+ /* use <eth0> or <192.168.10.10> style addresses. Anything except
+ this will make us try to get the "default" address.
+ NOTE: this is a changed behaviour since the released 4.1!
+ */
+ GetStr(&config->ftpport, nextarg);
+ break;
+ case 'p':
+ /* proxy tunnel for non-http protocols */
+ config->proxytunnel = toggle;
+ break;
+
+ case 'q': /* if used first, already taken care of, we do it like
+ this so we don't cause an error! */
+ break;
+ case 'Q':
+ /* QUOTE command to send to FTP server */
+ switch(nextarg[0]) {
+ case '-':
+ /* prefixed with a dash makes it a POST TRANSFER one */
+ nextarg++;
+ err = add2list(&config->postquote, nextarg);
+ break;
+ case '+':
+ /* prefixed with a plus makes it a just-before-transfer one */
+ nextarg++;
+ err = add2list(&config->prequote, nextarg);
+ break;
+ default:
+ err = add2list(&config->quote, nextarg);
+ break;
+ }
+ if(err)
+ return err;
+ break;
+ case 'r':
+ /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
+ (and won't actually be range by definition). The man page previously
+ claimed that to be a good way, why this code is added to work-around
+ it. */
+ if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
+ char buffer[32];
+ curl_off_t off;
+ warnf(config,
+ "A specified range MUST include at least one dash (-). "
+ "Appending one for you!\n");
+ off = curlx_strtoofft(nextarg, NULL, 10);
+ snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off);
+ Curl_safefree(config->range);
+ config->range = strdup(buffer);
+ if(!config->range)
+ return PARAM_NO_MEM;
+ }
+ {
+ /* byte range requested */
+ char *tmp_range;
+ tmp_range = nextarg;
+ while(*tmp_range != '\0') {
+ if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') {
+ warnf(config,"Invalid character is found in given range. "
+ "A specified range MUST have only digits in "
+ "\'start\'-\'stop\'. The server's response to this "
+ "request is uncertain.\n");
+ break;
+ }
+ tmp_range++;
+ }
+ /* byte range requested */
+ GetStr(&config->range, nextarg);
+ }
+ break;
+ case 'R':
+ /* use remote file's time */
+ config->remote_time = toggle;
+ break;
+ case 's':
+ /* don't show progress meter, don't show errors : */
+ if(toggle)
+ config->mute = config->noprogress = TRUE;
+ else
+ config->mute = config->noprogress = FALSE;
+ if(config->showerror < 0)
+ /* if still on the default value, set showerror to the reverse of
+ toggle. This is to allow -S and -s to be used in an independent
+ order but still have the same effect. */
+ config->showerror = (!toggle)?TRUE:FALSE; /* toggle off */
+ break;
+ case 'S':
+ /* show errors */
+ config->showerror = toggle?1:0; /* toggle on if used with -s */
+ break;
+ case 't':
+ /* Telnet options */
+ err = add2list(&config->telnet_options, nextarg);
+ if(err)
+ return err;
+ break;
+ case 'T':
+ /* we are uploading */
+ {
+ struct getout *url;
+ if(config->url_out || ((config->url_out = config->url_list) != NULL)) {
+ /* there's a node here, if it already is filled-in continue to find
+ an "empty" node */
+ while(config->url_out && (config->url_out->flags & GETOUT_UPLOAD))
+ config->url_out = config->url_out->next;
+ }
+
+ /* now there might or might not be an available node to fill in! */
+
+ if(config->url_out)
+ /* existing node */
+ url = config->url_out;
+ else
+ /* there was no free node, create one! */
+ url = new_getout(config);
+
+ if(!url)
+ return PARAM_NO_MEM;
+ else {
+ url->flags |= GETOUT_UPLOAD; /* mark -T used */
+ if(!*nextarg)
+ url->flags |= GETOUT_NOUPLOAD;
+ else {
+ /* "-" equals stdin, but keep the string around for now */
+ GetStr(&url->infile, nextarg);
+ }
+ }
+ }
+ break;
+ case 'u':
+ /* user:password */
+ GetStr(&config->userpwd, nextarg);
+ cleanarg(nextarg);
+ err = checkpasswd("host", &config->userpwd);
+ if(err)
+ return err;
+ break;
+ case 'U':
+ /* Proxy user:password */
+ GetStr(&config->proxyuserpwd, nextarg);
+ cleanarg(nextarg);
+ err = checkpasswd("proxy", &config->proxyuserpwd);
+ if(err)
+ return err;
+ break;
+ case 'v':
+ if(toggle) {
+ /* the '%' thing here will cause the trace get sent to stderr */
+ Curl_safefree(config->trace_dump);
+ config->trace_dump = strdup("%");
+ if(!config->trace_dump)
+ return PARAM_NO_MEM;
+ if(config->tracetype && (config->tracetype != TRACE_PLAIN))
+ warnf(config,
+ "-v, --verbose overrides an earlier trace/verbose option\n");
+ config->tracetype = TRACE_PLAIN;
+ }
+ else
+ /* verbose is disabled here */
+ config->tracetype = TRACE_NONE;
+ break;
+ case 'V':
+ {
+ const char *const *proto;
+
+ if(!toggle)
+ /* --no-version yields no output! */
+ break;
+
+ printf(CURL_ID "%s\n", curl_version());
+ if(curlinfo->protocols) {
+ printf("Protocols: ");
+ for(proto = curlinfo->protocols; *proto; ++proto) {
+ printf("%s ", *proto);
+ }
+ puts(""); /* newline */
+ }
+ if(curlinfo->features) {
+ unsigned int i;
+ printf("Features: ");
+ for(i = 0; i < sizeof(feats)/sizeof(feats[0]); i++) {
+ if(curlinfo->features & feats[i].bitmask)
+ printf("%s ", feats[i].name);
+ }
+#ifdef USE_METALINK
+ printf("Metalink ");
+#endif
+ puts(""); /* newline */
+ }
+ }
+ return PARAM_HELP_REQUESTED;
+ case 'w':
+ /* get the output string */
+ if('@' == *nextarg) {
+ /* the data begins with a '@' letter, it means that a file name
+ or - (stdin) follows */
+ FILE *file;
+ const char *fname;
+ nextarg++; /* pass the @ */
+ if(curlx_strequal("-", nextarg)) {
+ fname = "<stdin>";
+ file = stdin;
+ }
+ else {
+ fname = nextarg;
+ file = fopen(nextarg, "r");
+ }
+ err = file2string(&config->writeout, file);
+ if(file && (file != stdin))
+ fclose(file);
+ if(err)
+ return err;
+ if(!config->writeout)
+ warnf(config, "Failed to read %s", fname);
+ }
+ else
+ GetStr(&config->writeout, nextarg);
+ break;
+ case 'x':
+ /* proxy */
+ GetStr(&config->proxy, nextarg);
+ config->proxyver = CURLPROXY_HTTP;
+ break;
+ case 'X':
+ /* set custom request */
+ GetStr(&config->customrequest, nextarg);
+ break;
+ case 'y':
+ /* low speed time */
+ err = str2unum(&config->low_speed_time, nextarg);
+ if(err)
+ return err;
+ if(!config->low_speed_limit)
+ config->low_speed_limit = 1;
+ break;
+ case 'Y':
+ /* low speed limit */
+ err = str2unum(&config->low_speed_limit, nextarg);
+ if(err)
+ return err;
+ if(!config->low_speed_time)
+ config->low_speed_time = 30;
+ break;
+ case 'z': /* time condition coming up */
+ switch(*nextarg) {
+ case '+':
+ nextarg++;
+ default:
+ /* If-Modified-Since: (section 14.28 in RFC2068) */
+ config->timecond = CURL_TIMECOND_IFMODSINCE;
+ break;
+ case '-':
+ /* If-Unmodified-Since: (section 14.24 in RFC2068) */
+ config->timecond = CURL_TIMECOND_IFUNMODSINCE;
+ nextarg++;
+ break;
+ case '=':
+ /* Last-Modified: (section 14.29 in RFC2068) */
+ config->timecond = CURL_TIMECOND_LASTMOD;
+ nextarg++;
+ break;
+ }
+ now = time(NULL);
+ config->condtime=curl_getdate(nextarg, &now);
+ if(-1 == (int)config->condtime) {
+ /* now let's see if it is a file name to get the time from instead! */
+ struct_stat statbuf;
+ if(-1 == stat(nextarg, &statbuf)) {
+ /* failed, remove time condition */
+ config->timecond = CURL_TIMECOND_NONE;
+ warnf(config,
+ "Illegal date format for -z, --timecond (and not "
+ "a file name). Disabling time condition. "
+ "See curl_getdate(3) for valid date syntax.\n");
+ }
+ else {
+ /* pull the time out from the file */
+ config->condtime = statbuf.st_mtime;
+ }
+ }
+ break;
+ default: /* unknown flag */
+ return PARAM_OPTION_UNKNOWN;
+ }
+ hit = -1;
+
+ } while(!longopt && !singleopt && *++parse && !*usedarg);
+
+ return PARAM_OK;
+}
+
diff --git a/src/tool_getparam.h b/src/tool_getparam.h
new file mode 100644
index 000000000..38f0674f4
--- /dev/null
+++ b/src/tool_getparam.h
@@ -0,0 +1,49 @@
+#ifndef HEADER_CURL_TOOL_GETPARAM_H
+#define HEADER_CURL_TOOL_GETPARAM_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+typedef enum {
+ PARAM_OK = 0,
+ PARAM_OPTION_AMBIGUOUS,
+ PARAM_OPTION_UNKNOWN,
+ PARAM_REQUIRES_PARAMETER,
+ PARAM_BAD_USE,
+ PARAM_HELP_REQUESTED,
+ PARAM_GOT_EXTRA_PARAMETER,
+ PARAM_BAD_NUMERIC,
+ PARAM_NEGATIVE_NUMERIC,
+ PARAM_LIBCURL_DOESNT_SUPPORT,
+ PARAM_NO_MEM,
+ PARAM_LAST
+} ParameterError;
+
+struct Configurable;
+
+ParameterError getparameter(char *flag,
+ char *nextarg,
+ bool *usedarg,
+ struct Configurable *config);
+
+#endif /* HEADER_CURL_TOOL_GETPARAM_H */
+
diff --git a/src/tool_getpass.c b/src/tool_getpass.c
new file mode 100644
index 000000000..a3fffa9b3
--- /dev/null
+++ b/src/tool_getpass.c
@@ -0,0 +1,260 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifndef HAVE_GETPASS_R
+/* this file is only for systems without getpass_r() */
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+# include <termios.h>
+#elif defined(HAVE_TERMIO_H)
+# include <termio.h>
+#endif
+
+#ifdef __VMS
+# include descrip
+# include starlet
+# include iodef
+#endif
+
+#ifdef WIN32
+# include <conio.h>
+#endif
+
+#ifdef NETWARE
+# ifdef __NOVELL_LIBC__
+# include <screen.h>
+# else
+# include <nwconio.h>
+# endif
+#endif
+
+#define _MPRINTF_REPLACE
+#include <curl/mprintf.h>
+
+#include "tool_getpass.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef __VMS
+/* VMS implementation */
+char *getpass_r(const char *prompt, char *buffer, size_t buflen)
+{
+ long sts;
+ short chan;
+
+ /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4 */
+ /* distribution so I created this. May revert back later to */
+ /* struct _iosb iosb; */
+ struct _iosb
+ {
+ short int iosb$w_status; /* status */
+ short int iosb$w_bcnt; /* byte count */
+ int unused; /* unused */
+ } iosb;
+
+ $DESCRIPTOR(ttdesc, "TT");
+
+ buffer[0] = '\0';
+ sts = sys$assign(&ttdesc, &chan, 0, 0);
+ if(sts & 1) {
+ sts = sys$qiow(0, chan,
+ IO$_READPROMPT | IO$M_NOECHO,
+ &iosb, 0, 0, buffer, buflen, 0, 0,
+ prompt, strlen(prompt));
+
+ if((sts & 1) && (iosb.iosb$w_status & 1))
+ buffer[iosb.iosb$w_bcnt] = '\0';
+
+ sts = sys$dassgn(chan);
+ }
+ return buffer; /* we always return success */
+}
+#define DONE
+#endif /* __VMS */
+
+#ifdef __SYMBIAN32__
+# define getch() getchar()
+#endif
+
+#if defined(WIN32) || defined(__SYMBIAN32__)
+
+char *getpass_r(const char *prompt, char *buffer, size_t buflen)
+{
+ size_t i;
+ fputs(prompt, stderr);
+
+ for(i = 0; i < buflen; i++) {
+ buffer[i] = (char)getch();
+ if(buffer[i] == '\r' || buffer[i] == '\n') {
+ buffer[i] = '\0';
+ break;
+ }
+ else
+ if(buffer[i] == '\b')
+ /* remove this letter and if this is not the first key, remove the
+ previous one as well */
+ i = i - (i >= 1) ? 2 : 1;
+ }
+#ifndef __SYMBIAN32__
+ /* since echo is disabled, print a newline */
+ fputs("\n", stderr);
+#endif
+ /* if user didn't hit ENTER, terminate buffer */
+ if(i == buflen)
+ buffer[buflen-1] = '\0';
+
+ return buffer; /* we always return success */
+}
+#define DONE
+#endif /* WIN32 || __SYMBIAN32__ */
+
+#ifdef NETWARE
+/* NetWare implementation */
+#ifdef __NOVELL_LIBC__
+char *getpass_r(const char *prompt, char *buffer, size_t buflen)
+{
+ return getpassword(prompt, buffer, buflen);
+}
+#else
+char *getpass_r(const char *prompt, char *buffer, size_t buflen)
+{
+ size_t i = 0;
+
+ printf("%s", prompt);
+ do {
+ buffer[i++] = getch();
+ if(buffer[i-1] == '\b') {
+ /* remove this letter and if this is not the first key,
+ remove the previous one as well */
+ if(i > 1) {
+ printf("\b \b");
+ i = i - 2;
+ }
+ else {
+ RingTheBell();
+ i = i - 1;
+ }
+ }
+ else if(buffer[i-1] != 13)
+ putchar('*');
+
+ } while((buffer[i-1] != 13) && (i < buflen));
+ buffer[i-1] = '\0';
+ printf("\r\n");
+ return buffer;
+}
+#endif /* __NOVELL_LIBC__ */
+#define DONE
+#endif /* NETWARE */
+
+#ifndef DONE /* not previously provided */
+
+#ifdef HAVE_TERMIOS_H
+# define struct_term struct termios
+#elif defined(HAVE_TERMIO_H)
+# define struct_term struct termio
+#else
+# undef struct_term
+#endif
+
+static bool ttyecho(bool enable, int fd)
+{
+#ifdef struct_term
+ static struct_term withecho;
+ static struct_term noecho;
+#endif
+ if(!enable) {
+ /* disable echo by extracting the current 'withecho' mode and remove the
+ ECHO bit and set back the struct */
+#ifdef HAVE_TERMIOS_H
+ tcgetattr(fd, &withecho);
+ noecho = withecho;
+ noecho.c_lflag &= ~ECHO;
+ tcsetattr(fd, TCSANOW, &noecho);
+#elif defined(HAVE_TERMIO_H)
+ ioctl(fd, TCGETA, &withecho);
+ noecho = withecho;
+ noecho.c_lflag &= ~ECHO;
+ ioctl(fd, TCSETA, &noecho);
+#else
+ /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */
+ (void)fd;
+ return FALSE; /* not disabled */
+#endif
+ return TRUE; /* disabled */
+ }
+ else {
+ /* re-enable echo, assumes we disabled it before (and set the structs we
+ now use to reset the terminal status) */
+#ifdef HAVE_TERMIOS_H
+ tcsetattr(fd, TCSAFLUSH, &withecho);
+#elif defined(HAVE_TERMIO_H)
+ ioctl(fd, TCSETA, &withecho);
+#else
+ return FALSE; /* not enabled */
+#endif
+ return TRUE; /* enabled */
+ }
+}
+
+char *getpass_r(const char *prompt, /* prompt to display */
+ char *password, /* buffer to store password in */
+ size_t buflen) /* size of buffer to store password in */
+{
+ ssize_t nread;
+ bool disabled;
+ int fd = open("/dev/tty", O_RDONLY);
+ if(-1 == fd)
+ fd = 1; /* use stdin if the tty couldn't be used */
+
+ disabled = ttyecho(FALSE, fd); /* disable terminal echo */
+
+ fputs(prompt, stderr);
+ nread = read(fd, password, buflen);
+ if(nread > 0)
+ password[--nread] = '\0'; /* zero terminate where enter is stored */
+ else
+ password[0] = '\0'; /* got nothing */
+
+ if(disabled) {
+ /* if echo actually was disabled, add a newline */
+ fputs("\n", stderr);
+ (void)ttyecho(TRUE, fd); /* enable echo */
+ }
+
+ if(1 != fd)
+ close(fd);
+
+ return password; /* return pointer to buffer */
+}
+
+#endif /* DONE */
+#endif /* HAVE_GETPASS_R */
diff --git a/src/tool_getpass.h b/src/tool_getpass.h
new file mode 100644
index 000000000..d4fc7e231
--- /dev/null
+++ b/src/tool_getpass.h
@@ -0,0 +1,36 @@
+#ifndef HEADER_CURL_TOOL_GETPASS_H
+#define HEADER_CURL_TOOL_GETPASS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifndef HAVE_GETPASS_R
+/* If there's a system-provided function named like this, we trust it is
+ also found in one of the standard headers. */
+
+/*
+ * Returning NULL will abort the continued operation!
+ */
+char* getpass_r(const char *prompt, char* buffer, size_t buflen);
+#endif
+
+#endif /* HEADER_CURL_TOOL_GETPASS_H */
diff --git a/src/tool_help.c b/src/tool_help.c
new file mode 100644
index 000000000..124f6404d
--- /dev/null
+++ b/src/tool_help.c
@@ -0,0 +1,245 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "tool_panykey.h"
+#include "tool_help.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef MSDOS
+# define USE_WATT32
+#endif
+
+/*
+ * A few of these source lines are >80 columns wide, but that's only because
+ * breaking the strings narrower makes this chunk look even worse!
+ *
+ * Starting with 7.18.0, this list of command line options is sorted based
+ * on the long option name. It is not done automatically, although a command
+ * line like the following can help out:
+ *
+ * curl --help | cut -c5- | grep "^-" | sort
+ */
+
+static const char *const helptext[] = {
+ "Usage: curl [options...] <url>",
+ "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
+ " --anyauth Pick \"any\" authentication method (H)",
+ " -a, --append Append to target file when uploading (F/SFTP)",
+ " --basic Use HTTP Basic Authentication (H)",
+ " --cacert FILE CA certificate to verify peer against (SSL)",
+ " --capath DIR CA directory to verify peer against (SSL)",
+ " -E, --cert CERT[:PASSWD] Client certificate file and password (SSL)",
+ " --cert-type TYPE Certificate file type (DER/PEM/ENG) (SSL)",
+ " --ciphers LIST SSL ciphers to use (SSL)",
+ " --compressed Request compressed response (using deflate or gzip)",
+ " -K, --config FILE Specify which config file to read",
+ " --connect-timeout SECONDS Maximum time allowed for connection",
+ " -C, --continue-at OFFSET Resumed transfer offset",
+ " -b, --cookie STRING/FILE String or file to read cookies from (H)",
+ " -c, --cookie-jar FILE Write cookies to this file after operation (H)",
+ " --create-dirs Create necessary local directory hierarchy",
+ " --crlf Convert LF to CRLF in upload",
+ " --crlfile FILE Get a CRL list in PEM format from the given file",
+ " -d, --data DATA HTTP POST data (H)",
+ " --data-ascii DATA HTTP POST ASCII data (H)",
+ " --data-binary DATA HTTP POST binary data (H)",
+ " --data-urlencode DATA HTTP POST data url encoded (H)",
+ " --delegation STRING GSS-API delegation permission",
+ " --digest Use HTTP Digest Authentication (H)",
+ " --disable-eprt Inhibit using EPRT or LPRT (F)",
+ " --disable-epsv Inhibit using EPSV (F)",
+ " -D, --dump-header FILE Write the headers to this file",
+ " --egd-file FILE EGD socket path for random data (SSL)",
+ " --engine ENGINGE Crypto engine (SSL). \"--engine list\" for list",
+#ifdef USE_ENVIRONMENT
+ " --environment Write results to environment variables (RISC OS)",
+#endif
+ " -f, --fail Fail silently (no output at all) on HTTP errors (H)",
+ " -F, --form CONTENT Specify HTTP multipart POST data (H)",
+ " --form-string STRING Specify HTTP multipart POST data (H)",
+ " --ftp-account DATA Account data string (F)",
+ " --ftp-alternative-to-user COMMAND "
+ "String to replace \"USER [name]\" (F)",
+ " --ftp-create-dirs Create the remote dirs if not present (F)",
+ " --ftp-method [MULTICWD/NOCWD/SINGLECWD] Control CWD usage (F)",
+ " --ftp-pasv Use PASV/EPSV instead of PORT (F)",
+ " -P, --ftp-port ADR Use PORT with given address instead of PASV (F)",
+ " --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
+ " --ftp-pret Send PRET before PASV (for drftpd) (F)",
+ " --ftp-ssl-ccc Send CCC after authenticating (F)",
+ " --ftp-ssl-ccc-mode ACTIVE/PASSIVE Set CCC mode (F)",
+ " --ftp-ssl-control Require SSL/TLS for ftp login, "
+ "clear for transfer (F)",
+ " -G, --get Send the -d data with a HTTP GET (H)",
+ " -g, --globoff Disable URL sequences and ranges using {} and []",
+ " -H, --header LINE Custom header to pass to server (H)",
+ " -I, --head Show document info only",
+ " -h, --help This help text",
+ " --hostpubmd5 MD5 "
+ "Hex encoded MD5 string of the host public key. (SSH)",
+ " -0, --http1.0 Use HTTP 1.0 (H)",
+ " --ignore-content-length Ignore the HTTP Content-Length header",
+ " -i, --include Include protocol headers in the output (H/F)",
+ " -k, --insecure Allow connections to SSL sites without certs (H)",
+ " --interface INTERFACE Specify network interface/address to use",
+ " -4, --ipv4 Resolve name to IPv4 address",
+ " -6, --ipv6 Resolve name to IPv6 address",
+ " -j, --junk-session-cookies Ignore session cookies read from file (H)",
+ " --keepalive-time SECONDS Interval between keepalive probes",
+ " --key KEY Private key file name (SSL/SSH)",
+ " --key-type TYPE Private key file type (DER/PEM/ENG) (SSL)",
+ " --krb LEVEL Enable Kerberos with specified security level (F)",
+#ifndef CURL_DISABLE_LIBCURL_OPTION
+ " --libcurl FILE Dump libcurl equivalent code of this command line",
+#endif
+ " --limit-rate RATE Limit transfer speed to this rate",
+ " -l, --list-only List only names of an FTP directory (F)",
+ " --local-port RANGE Force use of these local port numbers",
+ " -L, --location Follow redirects (H)",
+ " --location-trusted like --location and send auth to other hosts (H)",
+ " -M, --manual Display the full manual",
+ " --mail-from FROM Mail from this address",
+ " --mail-rcpt TO Mail to this receiver(s)",
+ " --mail-auth AUTH Originator address of the original email",
+ " --max-filesize BYTES Maximum file size to download (H/F)",
+ " --max-redirs NUM Maximum number of redirects allowed (H)",
+ " -m, --max-time SECONDS Maximum time allowed for the transfer",
+ " --metalink Process given URLs as metalink XML file",
+ " --negotiate Use HTTP Negotiate Authentication (H)",
+ " -n, --netrc Must read .netrc for user name and password",
+ " --netrc-optional Use either .netrc or URL; overrides -n",
+ " --netrc-file FILE Set up the netrc filename to use",
+ " -N, --no-buffer Disable buffering of the output stream",
+ " --no-keepalive Disable keepalive use on the connection",
+ " --no-sessionid Disable SSL session-ID reusing (SSL)",
+ " --noproxy List of hosts which do not use proxy",
+ " --ntlm Use HTTP NTLM authentication (H)",
+ " -o, --output FILE Write output to <file> instead of stdout",
+ " --pass PASS Pass phrase for the private key (SSL/SSH)",
+ " --post301 "
+ "Do not switch to GET after following a 301 redirect (H)",
+ " --post302 "
+ "Do not switch to GET after following a 302 redirect (H)",
+ " --post303 "
+ "Do not switch to GET after following a 303 redirect (H)",
+ " -#, --progress-bar Display transfer progress as a progress bar",
+ " --proto PROTOCOLS Enable/disable specified protocols",
+ " --proto-redir PROTOCOLS "
+ "Enable/disable specified protocols on redirect",
+ " -x, --proxy [PROTOCOL://]HOST[:PORT] Use proxy on given port",
+ " --proxy-anyauth Pick \"any\" proxy authentication method (H)",
+ " --proxy-basic Use Basic authentication on the proxy (H)",
+ " --proxy-digest Use Digest authentication on the proxy (H)",
+ " --proxy-negotiate Use Negotiate authentication on the proxy (H)",
+ " --proxy-ntlm Use NTLM authentication on the proxy (H)",
+ " -U, --proxy-user USER[:PASSWORD] Proxy user and password",
+ " --proxy1.0 HOST[:PORT] Use HTTP/1.0 proxy on given port",
+ " -p, --proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)",
+ " --pubkey KEY Public key file name (SSH)",
+ " -Q, --quote CMD Send command(s) to server before transfer (F/SFTP)",
+ " --random-file FILE File for reading random data from (SSL)",
+ " -r, --range RANGE Retrieve only the bytes within a range",
+ " --raw Do HTTP \"raw\", without any transfer decoding (H)",
+ " -e, --referer Referer URL (H)",
+ " -J, --remote-header-name Use the header-provided filename (H)",
+ " -O, --remote-name Write output to a file named as the remote file",
+ " --remote-name-all Use the remote file name for all URLs",
+ " -R, --remote-time Set the remote file's time on the local output",
+ " -X, --request COMMAND Specify request command to use",
+ " --resolve HOST:PORT:ADDRESS Force resolve of HOST:PORT to ADDRESS",
+ " --retry NUM "
+ "Retry request NUM times if transient problems occur",
+ " --retry-delay SECONDS "
+ "When retrying, wait this many seconds between each",
+ " --retry-max-time SECONDS Retry only within this period",
+ " -S, --show-error "
+ "Show error. With -s, make curl show errors when they occur",
+ " -s, --silent Silent mode. Don't output anything",
+ " --socks4 HOST[:PORT] SOCKS4 proxy on given host + port",
+ " --socks4a HOST[:PORT] SOCKS4a proxy on given host + port",
+ " --socks5 HOST[:PORT] SOCKS5 proxy on given host + port",
+ " --socks5-hostname HOST[:PORT] "
+ "SOCKS5 proxy, pass host name to proxy",
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ " --socks5-gssapi-service NAME SOCKS5 proxy service name for gssapi",
+ " --socks5-gssapi-nec Compatibility with NEC SOCKS5 server",
+#endif
+ " -Y, --speed-limit RATE "
+ "Stop transfers below speed-limit for 'speed-time' secs",
+ " -y, --speed-time SECONDS "
+ "Time for trig speed-limit abort. Defaults to 30",
+ " --ssl Try SSL/TLS (FTP, IMAP, POP3, SMTP)",
+ " --ssl-reqd Require SSL/TLS (FTP, IMAP, POP3, SMTP)",
+ " -2, --sslv2 Use SSLv2 (SSL)",
+ " -3, --sslv3 Use SSLv3 (SSL)",
+ " --ssl-allow-beast Allow security flaw to improve interop (SSL)",
+ " --stderr FILE Where to redirect stderr. - means stdout",
+ " --tcp-nodelay Use the TCP_NODELAY option",
+ " -t, --telnet-option OPT=VAL Set telnet option",
+ " --tftp-blksize VALUE Set TFTP BLKSIZE option (must be >512)",
+ " -z, --time-cond TIME Transfer based on a time condition",
+ " -1, --tlsv1 Use TLSv1 (SSL)",
+ " --trace FILE Write a debug trace to the given file",
+ " --trace-ascii FILE Like --trace but without the hex output",
+ " --trace-time Add time stamps to trace/verbose output",
+ " --tr-encoding Request compressed transfer encoding (H)",
+ " -T, --upload-file FILE Transfer FILE to destination",
+ " --url URL URL to work with",
+ " -B, --use-ascii Use ASCII/text transfer",
+ " -u, --user USER[:PASSWORD] Server user and password",
+ " --tlsuser USER TLS username",
+ " --tlspassword STRING TLS password",
+ " --tlsauthtype STRING TLS authentication type (default SRP)",
+ " -A, --user-agent STRING User-Agent to send to server (H)",
+ " -v, --verbose Make the operation more talkative",
+ " -V, --version Show version number and quit",
+#ifdef USE_WATT32
+ " --wdebug Turn on Watt-32 debugging",
+#endif
+ " -w, --write-out FORMAT What to output after completion",
+ " --xattr Store metadata in extended file attributes",
+ " -q If used as the first parameter disables .curlrc",
+ NULL
+};
+
+#ifdef NETWARE
+# define PRINT_LINES_PAUSE 23
+#endif
+
+#ifdef __SYMBIAN32__
+# define PRINT_LINES_PAUSE 16
+#endif
+
+void tool_help(void)
+{
+ int i;
+ for(i = 0; helptext[i]; i++) {
+ puts(helptext[i]);
+#ifdef PRINT_LINES_PAUSE
+ if(i && ((i % PRINT_LINES_PAUSE) == 0))
+ tool_pressanykey();
+#endif
+ }
+}
+
diff --git a/src/tool_help.h b/src/tool_help.h
new file mode 100644
index 000000000..1b757dc80
--- /dev/null
+++ b/src/tool_help.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TOOL_HELP_H
+#define HEADER_CURL_TOOL_HELP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+void tool_help(void);
+
+#endif /* HEADER_CURL_TOOL_HELP_H */
+
diff --git a/src/tool_helpers.c b/src/tool_helpers.c
new file mode 100644
index 000000000..ae8aaaf32
--- /dev/null
+++ b/src/tool_helpers.c
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+#include "tool_getparam.h"
+#include "tool_helpers.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+** Helper functions that are used from more tha one source file.
+*/
+
+const char *param2text(int res)
+{
+ ParameterError error = (ParameterError)res;
+ switch(error) {
+ case PARAM_GOT_EXTRA_PARAMETER:
+ return "had unsupported trailing garbage";
+ case PARAM_OPTION_UNKNOWN:
+ return "is unknown";
+ case PARAM_OPTION_AMBIGUOUS:
+ return "is ambiguous";
+ case PARAM_REQUIRES_PARAMETER:
+ return "requires parameter";
+ case PARAM_BAD_USE:
+ return "is badly used here";
+ case PARAM_BAD_NUMERIC:
+ return "expected a proper numerical parameter";
+ case PARAM_NEGATIVE_NUMERIC:
+ return "expected a positive numerical parameter";
+ case PARAM_LIBCURL_DOESNT_SUPPORT:
+ return "the installed libcurl version doesn't support this";
+ case PARAM_NO_MEM:
+ return "out of memory";
+ default:
+ return "unknown error";
+ }
+}
+
+int SetHTTPrequest(struct Configurable *config, HttpReq req, HttpReq *store)
+{
+ if((*store == HTTPREQ_UNSPEC) ||
+ (*store == req)) {
+ *store = req;
+ return 0;
+ }
+ warnf(config, "You can only select one HTTP request!\n");
+ return 1;
+}
+
diff --git a/src/tool_helpers.h b/src/tool_helpers.h
new file mode 100644
index 000000000..c0bcd8910
--- /dev/null
+++ b/src/tool_helpers.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_TOOL_HELPERS_H
+#define HEADER_CURL_TOOL_HELPERS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+const char *param2text(int res);
+
+int SetHTTPrequest(struct Configurable *config, HttpReq req, HttpReq *store);
+
+#endif /* HEADER_CURL_TOOL_HELPERS_H */
+
diff --git a/src/tool_homedir.c b/src/tool_homedir.c
new file mode 100644
index 000000000..61cc02afb
--- /dev/null
+++ b/src/tool_homedir.c
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef __VMS
+# include <unixlib.h>
+#endif
+
+#include "tool_homedir.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+static char *GetEnv(const char *variable, char do_expand)
+{
+ char *env = NULL;
+#ifdef WIN32
+ char buf1[1024], buf2[1024];
+ DWORD rc;
+
+ /* Don't use getenv(); it doesn't find variable added after program was
+ * started. Don't accept truncated results (i.e. rc >= sizeof(buf1)). */
+
+ rc = GetEnvironmentVariable(variable, buf1, sizeof(buf1));
+ if(rc > 0 && rc < sizeof(buf1)) {
+ env = buf1;
+ variable = buf1;
+ }
+ if(do_expand && strchr(variable,'%')) {
+ /* buf2 == variable if not expanded */
+ rc = ExpandEnvironmentStrings (variable, buf2, sizeof(buf2));
+ if(rc > 0 && rc < sizeof(buf2) &&
+ !strchr(buf2,'%')) /* no vars still unexpanded */
+ env = buf2;
+ }
+#else
+ (void)do_expand;
+#ifdef __VMS
+ env = getenv(variable);
+ if(env && strcmp("HOME",variable) == 0) {
+ env = decc_translate_vms(env);
+ }
+#else
+ /* no length control */
+ env = getenv(variable);
+#endif
+#endif
+ return (env && env[0]) ? strdup(env) : NULL;
+}
+
+/* return the home directory of the current user as an allocated string */
+char *homedir(void)
+{
+ char *home;
+
+ home = GetEnv("CURL_HOME", FALSE);
+ if(home)
+ return home;
+
+ home = GetEnv("HOME", FALSE);
+ if(home)
+ return home;
+
+#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
+ {
+ struct passwd *pw = getpwuid(geteuid());
+
+ if(pw) {
+#ifdef __VMS
+ home = decc_translate_vms(pw->pw_dir);
+#else
+ home = pw->pw_dir;
+#endif
+ if(home && home[0])
+ home = strdup(home);
+ else
+ home = NULL;
+ }
+ }
+#endif /* PWD-stuff */
+#ifdef WIN32
+ home = GetEnv("APPDATA", TRUE);
+ if(!home)
+ home = GetEnv("%USERPROFILE%\\Application Data", TRUE); /* Normally only
+ on Win-2K/XP */
+#endif /* WIN32 */
+ return home;
+}
diff --git a/src/tool_homedir.h b/src/tool_homedir.h
new file mode 100644
index 000000000..d58861555
--- /dev/null
+++ b/src/tool_homedir.h
@@ -0,0 +1,28 @@
+#ifndef HEADER_CURL_TOOL_HOMEDIR_H
+#define HEADER_CURL_TOOL_HOMEDIR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+char *homedir(void);
+
+#endif /* HEADER_CURL_TOOL_HOMEDIR_H */
diff --git a/src/tool_libinfo.c b/src/tool_libinfo.c
new file mode 100644
index 000000000..81b6680c8
--- /dev/null
+++ b/src/tool_libinfo.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_libinfo.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/* global variable definitions, for libcurl run-time info */
+
+curl_version_info_data *curlinfo = NULL;
+long built_in_protos = 0;
+
+/*
+ * libcurl_info_init: retrieves run-time information about libcurl,
+ * setting a global pointer 'curlinfo' to libcurl's run-time info
+ * struct, and a global bit pattern 'built_in_protos' composed of
+ * CURLPROTO_* bits indicating which protocols are actually built
+ * into library being used.
+ */
+
+CURLcode get_libcurl_info(void)
+{
+ static struct proto_name_pattern {
+ const char *proto_name;
+ long proto_pattern;
+ } const possibly_built_in[] = {
+ { "dict", CURLPROTO_DICT },
+ { "file", CURLPROTO_FILE },
+ { "ftp", CURLPROTO_FTP },
+ { "ftps", CURLPROTO_FTPS },
+ { "gopher", CURLPROTO_GOPHER },
+ { "http", CURLPROTO_HTTP },
+ { "https", CURLPROTO_HTTPS },
+ { "imap", CURLPROTO_IMAP },
+ { "imaps", CURLPROTO_IMAPS },
+ { "ldap", CURLPROTO_LDAP },
+ { "ldaps", CURLPROTO_LDAPS },
+ { "pop3", CURLPROTO_POP3 },
+ { "pop3s", CURLPROTO_POP3S },
+ { "rtmp", CURLPROTO_RTMP },
+ { "rtsp", CURLPROTO_RTSP },
+ { "scp", CURLPROTO_SCP },
+ { "sftp", CURLPROTO_SFTP },
+ { "smtp", CURLPROTO_SMTP },
+ { "smtps", CURLPROTO_SMTPS },
+ { "telnet", CURLPROTO_TELNET },
+ { "tftp", CURLPROTO_TFTP },
+ { NULL, 0 }
+ };
+
+ struct proto_name_pattern const *p;
+ const char *const *proto;
+
+ /* Pointer to libcurl's run-time version information */
+ curlinfo = curl_version_info(CURLVERSION_NOW);
+ if(!curlinfo)
+ return CURLE_FAILED_INIT;
+
+ /* Build CURLPROTO_* bit pattern with libcurl's built-in protocols */
+ built_in_protos = 0;
+ if(curlinfo->protocols) {
+ for(proto = curlinfo->protocols; *proto; proto++) {
+ for(p = possibly_built_in; p->proto_name; p++) {
+ if(curlx_raw_equal(*proto, p->proto_name)) {
+ built_in_protos |= p->proto_pattern;
+ break;
+ }
+ }
+ }
+ }
+
+ return CURLE_OK;
+}
+
diff --git a/src/tool_libinfo.h b/src/tool_libinfo.h
new file mode 100644
index 000000000..5c149d916
--- /dev/null
+++ b/src/tool_libinfo.h
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_TOOL_LIBINFO_H
+#define HEADER_CURL_TOOL_LIBINFO_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+/* global variable declarations, for libcurl run-time info */
+
+extern curl_version_info_data *curlinfo;
+extern long built_in_protos;
+
+CURLcode get_libcurl_info(void);
+
+#endif /* HEADER_CURL_TOOL_LIBINFO_H */
+
diff --git a/src/tool_main.c b/src/tool_main.c
new file mode 100644
index 000000000..be1b3fcaa
--- /dev/null
+++ b/src/tool_main.c
@@ -0,0 +1,110 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_convert.h"
+#include "tool_operate.h"
+#include "tool_panykey.h"
+#include "tool_vms.h"
+#include "tool_main.h"
+
+/*
+ * This is low-level hard-hacking memory leak tracking and similar. Using
+ * the library level code from this client-side is ugly, but we do this
+ * anyway for convenience.
+ */
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef __VMS
+static int vms_show = 0;
+#endif
+
+/*
+ * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
+ * open before starting to run. Otherwise, the first three network
+ * sockets opened by curl could be used for input sources, downloaded data
+ * or error logs as they will effectively be stdin, stdout and/or stderr.
+ */
+static void main_checkfds(void)
+{
+#ifdef HAVE_PIPE
+ int fd[2] = { STDIN_FILENO, STDIN_FILENO };
+ while(fd[0] == STDIN_FILENO ||
+ fd[0] == STDOUT_FILENO ||
+ fd[0] == STDERR_FILENO ||
+ fd[1] == STDIN_FILENO ||
+ fd[1] == STDOUT_FILENO ||
+ fd[1] == STDERR_FILENO)
+ if(pipe(fd) < 0)
+ return; /* Out of handles. This isn't really a big problem now, but
+ will be when we try to create a socket later. */
+ close(fd[0]);
+ close(fd[1]);
+#endif
+}
+
+/*
+** curl tool main function.
+*/
+int main(int argc, char *argv[])
+{
+ int res;
+ struct Configurable config;
+
+ memset(&config, 0, sizeof(struct Configurable));
+
+ config.errors = stderr; /* default errors to stderr */
+
+ main_checkfds();
+
+ res = operate(&config, argc, argv);
+
+#ifdef __SYMBIAN32__
+ if(config.showerror)
+ tool_pressanykey();
+#endif
+
+ free_config_fields(&config);
+
+#ifdef __NOVELL_LIBC__
+ if(getenv("_IN_NETWARE_BASH_") == NULL)
+ tool_pressanykey();
+#endif
+
+#ifdef __VMS
+ vms_special_exit(res, vms_show);
+#else
+ return res;
+#endif
+}
+
diff --git a/src/tool_main.h b/src/tool_main.h
new file mode 100644
index 000000000..9a7972fdd
--- /dev/null
+++ b/src/tool_main.h
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_TOOL_MAIN_H
+#define HEADER_CURL_TOOL_MAIN_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#define DEFAULT_MAXREDIRS 50L
+
+#define RETRY_SLEEP_DEFAULT 1000L /* ms */
+#define RETRY_SLEEP_MAX 600000L /* ms == 10 minutes */
+
+#ifndef STDIN_FILENO
+# define STDIN_FILENO fileno(stdin)
+#endif
+
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO fileno(stdout)
+#endif
+
+#ifndef STDERR_FILENO
+# define STDERR_FILENO fileno(stderr)
+#endif
+
+#endif /* HEADER_CURL_TOOL_MAIN_H */
+
diff --git a/src/tool_metalink.c b/src/tool_metalink.c
new file mode 100644
index 000000000..42b514ca3
--- /dev/null
+++ b/src/tool_metalink.c
@@ -0,0 +1,906 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef USE_METALINK
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <sys/stat.h>
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef USE_SSLEAY
+# ifdef USE_OPENSSL
+# include <openssl/md5.h>
+# include <openssl/sha.h>
+# else
+# include <md5.h>
+# include <sha.h>
+# endif
+#elif defined(USE_GNUTLS_NETTLE)
+# include <nettle/md5.h>
+# include <nettle/sha.h>
+# define MD5_CTX struct md5_ctx
+# define SHA_CTX struct sha1_ctx
+# define SHA256_CTX struct sha256_ctx
+#elif defined(USE_GNUTLS)
+# include <gcrypt.h>
+# define MD5_CTX gcry_md_hd_t
+# define SHA_CTX gcry_md_hd_t
+# define SHA256_CTX gcry_md_hd_t
+#elif defined(USE_NSS)
+# include <nss.h>
+# include <pk11pub.h>
+# define MD5_CTX void *
+# define SHA_CTX void *
+# define SHA256_CTX void *
+# ifdef HAVE_NSS_INITCONTEXT
+ static NSSInitContext *nss_context;
+# endif
+#elif defined(__MAC_10_4) || defined(__IPHONE_5_0)
+/* For Apple operating systems: CommonCrypto has the functions we need.
+ The library's headers are even backward-compatible with OpenSSL's
+ headers as long as we define COMMON_DIGEST_FOR_OPENSSL first.
+
+ These functions are available on Tiger and later, as well as iOS 5.0
+ and later. If you're building for an older cat, well, sorry. */
+# define COMMON_DIGEST_FOR_OPENSSL
+# include <CommonCrypto/CommonDigest.h>
+#elif defined(_WIN32)
+/* For Windows: If no other crypto library is provided, we fallback
+ to the hash functions provided within the Microsoft Windows CryptoAPI */
+# include <wincrypt.h>
+/* Custom structure in order to store the required provider and hash handle */
+struct win32_crypto_hash {
+ HCRYPTPROV hCryptProv;
+ HCRYPTHASH hHash;
+};
+/* Custom Microsoft AES Cryptographic Provider defines required for MinGW */
+# ifndef ALG_SID_SHA_256
+# define ALG_SID_SHA_256 12
+# endif
+# ifndef CALG_SHA_256
+# define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
+# endif
+# define MD5_CTX struct win32_crypto_hash
+# define SHA_CTX struct win32_crypto_hash
+# define SHA256_CTX struct win32_crypto_hash
+#else
+# error "Can't compile METALINK support without a crypto library."
+#endif
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_getparam.h"
+#include "tool_paramhlp.h"
+#include "tool_cfgable.h"
+#include "tool_metalink.h"
+#include "tool_msgs.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/* Copied from tool_getparam.c */
+#define GetStr(str,val) do { \
+ if(*(str)) { \
+ free(*(str)); \
+ *(str) = NULL; \
+ } \
+ if((val)) \
+ *(str) = strdup((val)); \
+ if(!(val)) \
+ return PARAM_NO_MEM; \
+} WHILE_FALSE
+
+#ifdef USE_GNUTLS_NETTLE
+
+static int MD5_Init(MD5_CTX *ctx)
+{
+ md5_init(ctx);
+ return 1;
+}
+
+static void MD5_Update(MD5_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ md5_update(ctx, inputLen, input);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+ md5_digest(ctx, 16, digest);
+}
+
+static int SHA1_Init(SHA_CTX *ctx)
+{
+ sha1_init(ctx);
+ return 1;
+}
+
+static void SHA1_Update(SHA_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ sha1_update(ctx, inputLen, input);
+}
+
+static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
+{
+ sha1_digest(ctx, 20, digest);
+}
+
+static int SHA256_Init(SHA256_CTX *ctx)
+{
+ sha256_init(ctx);
+ return 1;
+}
+
+static void SHA256_Update(SHA256_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ sha256_update(ctx, inputLen, input);
+}
+
+static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
+{
+ sha256_digest(ctx, 32, digest);
+}
+
+#elif defined(USE_GNUTLS)
+
+static int MD5_Init(MD5_CTX *ctx)
+{
+ gcry_md_open(ctx, GCRY_MD_MD5, 0);
+ return 1;
+}
+
+static void MD5_Update(MD5_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ gcry_md_write(*ctx, input, inputLen);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+ memcpy(digest, gcry_md_read(*ctx, 0), 16);
+ gcry_md_close(*ctx);
+}
+
+static int SHA1_Init(SHA_CTX *ctx)
+{
+ gcry_md_open(ctx, GCRY_MD_SHA1, 0);
+ return 1;
+}
+
+static void SHA1_Update(SHA_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ gcry_md_write(*ctx, input, inputLen);
+}
+
+static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
+{
+ memcpy(digest, gcry_md_read(*ctx, 0), 20);
+ gcry_md_close(*ctx);
+}
+
+static int SHA256_Init(SHA256_CTX *ctx)
+{
+ gcry_md_open(ctx, GCRY_MD_SHA256, 0);
+ return 1;
+}
+
+static void SHA256_Update(SHA256_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ gcry_md_write(*ctx, input, inputLen);
+}
+
+static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
+{
+ memcpy(digest, gcry_md_read(*ctx, 0), 32);
+ gcry_md_close(*ctx);
+}
+
+#elif defined(USE_NSS)
+
+static int nss_hash_init(void **pctx, SECOidTag hash_alg)
+{
+ PK11Context *ctx;
+
+ /* we have to initialize NSS if not initialized alraedy */
+#ifdef HAVE_NSS_INITCONTEXT
+ if(!NSS_IsInitialized() && !nss_context) {
+ static NSSInitParameters params;
+ params.length = sizeof params;
+ nss_context = NSS_InitContext("", "", "", "", &params, NSS_INIT_READONLY
+ | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
+ | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
+ }
+#endif
+
+ ctx = PK11_CreateDigestContext(hash_alg);
+ if(!ctx)
+ return /* failure */ 0;
+
+ if(PK11_DigestBegin(ctx) != SECSuccess) {
+ PK11_DestroyContext(ctx, PR_TRUE);
+ return /* failure */ 0;
+ }
+
+ *pctx = ctx;
+ return /* success */ 1;
+}
+
+static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len)
+{
+ PK11Context *ctx = *pctx;
+ unsigned int outlen;
+ PK11_DigestFinal(ctx, out, &outlen, len);
+ PK11_DestroyContext(ctx, PR_TRUE);
+}
+
+static int MD5_Init(MD5_CTX *pctx)
+{
+ return nss_hash_init(pctx, SEC_OID_MD5);
+}
+
+static void MD5_Update(MD5_CTX *pctx,
+ const unsigned char *input,
+ unsigned int input_len)
+{
+ PK11_DigestOp(*pctx, input, input_len);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
+{
+ nss_hash_final(pctx, digest, 16);
+}
+
+static int SHA1_Init(SHA_CTX *pctx)
+{
+ return nss_hash_init(pctx, SEC_OID_SHA1);
+}
+
+static void SHA1_Update(SHA_CTX *pctx,
+ const unsigned char *input,
+ unsigned int input_len)
+{
+ PK11_DigestOp(*pctx, input, input_len);
+}
+
+static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
+{
+ nss_hash_final(pctx, digest, 20);
+}
+
+static int SHA256_Init(SHA256_CTX *pctx)
+{
+ return nss_hash_init(pctx, SEC_OID_SHA256);
+}
+
+static void SHA256_Update(SHA256_CTX *pctx,
+ const unsigned char *input,
+ unsigned int input_len)
+{
+ PK11_DigestOp(*pctx, input, input_len);
+}
+
+static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
+{
+ nss_hash_final(pctx, digest, 32);
+}
+
+#elif defined(_WIN32) && !defined(USE_SSLEAY)
+
+static void win32_crypto_final(struct win32_crypto_hash *ctx,
+ unsigned char *digest,
+ unsigned int digestLen)
+{
+ unsigned long length;
+ CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
+ if(length == digestLen)
+ CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
+ if(ctx->hHash)
+ CryptDestroyHash(ctx->hHash);
+ if(ctx->hCryptProv)
+ CryptReleaseContext(ctx->hCryptProv, 0);
+}
+
+static int MD5_Init(MD5_CTX *ctx)
+{
+ if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
+ }
+ return 1;
+}
+
+static void MD5_Update(MD5_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+ win32_crypto_final(ctx, digest, 16);
+}
+
+static int SHA1_Init(SHA_CTX *ctx)
+{
+ if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
+ }
+ return 1;
+}
+
+static void SHA1_Update(SHA_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
+}
+
+static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
+{
+ win32_crypto_final(ctx, digest, 20);
+}
+
+static int SHA256_Init(SHA256_CTX *ctx)
+{
+ if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
+ PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
+ CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
+ }
+ return 1;
+}
+
+static void SHA256_Update(SHA256_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
+}
+
+static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
+{
+ win32_crypto_final(ctx, digest, 32);
+}
+
+#endif /* CRYPTO LIBS */
+
+const digest_params MD5_DIGEST_PARAMS[] = {
+ {
+ (Curl_digest_init_func) MD5_Init,
+ (Curl_digest_update_func) MD5_Update,
+ (Curl_digest_final_func) MD5_Final,
+ sizeof(MD5_CTX),
+ 16
+ }
+};
+
+const digest_params SHA1_DIGEST_PARAMS[] = {
+ {
+ (Curl_digest_init_func) SHA1_Init,
+ (Curl_digest_update_func) SHA1_Update,
+ (Curl_digest_final_func) SHA1_Final,
+ sizeof(SHA_CTX),
+ 20
+ }
+};
+
+const digest_params SHA256_DIGEST_PARAMS[] = {
+ {
+ (Curl_digest_init_func) SHA256_Init,
+ (Curl_digest_update_func) SHA256_Update,
+ (Curl_digest_final_func) SHA256_Final,
+ sizeof(SHA256_CTX),
+ 32
+ }
+};
+
+static const metalink_digest_def SHA256_DIGEST_DEF[] = {
+ {"sha-256", SHA256_DIGEST_PARAMS}
+};
+
+static const metalink_digest_def SHA1_DIGEST_DEF[] = {
+ {"sha-1", SHA1_DIGEST_PARAMS}
+};
+
+static const metalink_digest_def MD5_DIGEST_DEF[] = {
+ {"md5", MD5_DIGEST_PARAMS}
+};
+
+/*
+ * The alias of supported hash functions in the order by preference
+ * (basically stronger hash comes first). We included "sha-256" and
+ * "sha256". The former is the name defined in the IANA registry named
+ * "Hash Function Textual Names". The latter is widely (and
+ * historically) used in Metalink version 3.
+ */
+static const metalink_digest_alias digest_aliases[] = {
+ {"sha-256", SHA256_DIGEST_DEF},
+ {"sha256", SHA256_DIGEST_DEF},
+ {"sha-1", SHA1_DIGEST_DEF},
+ {"sha1", SHA1_DIGEST_DEF},
+ {"md5", MD5_DIGEST_DEF},
+ {NULL, NULL}
+};
+
+digest_context *Curl_digest_init(const digest_params *dparams)
+{
+ digest_context *ctxt;
+
+ /* Create digest context */
+ ctxt = malloc(sizeof *ctxt);
+
+ if(!ctxt)
+ return ctxt;
+
+ ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
+
+ if(!ctxt->digest_hashctx) {
+ free(ctxt);
+ return NULL;
+ }
+
+ ctxt->digest_hash = dparams;
+
+ if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
+ free(ctxt);
+ return NULL;
+ }
+
+ return ctxt;
+}
+
+int Curl_digest_update(digest_context *context,
+ const unsigned char *data,
+ unsigned int len)
+{
+ (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
+
+ return 0;
+}
+
+int Curl_digest_final(digest_context *context, unsigned char *result)
+{
+ (*context->digest_hash->digest_final)(result, context->digest_hashctx);
+
+ free(context->digest_hashctx);
+ free(context);
+
+ return 0;
+}
+
+static unsigned char hex_to_uint(const char *s)
+{
+ int v[2];
+ int i;
+ for(i = 0; i < 2; ++i) {
+ v[i] = Curl_raw_toupper(s[i]);
+ if('0' <= v[i] && v[i] <= '9') {
+ v[i] -= '0';
+ }
+ else if('A' <= v[i] && v[i] <= 'Z') {
+ v[i] -= 'A'-10;
+ }
+ }
+ return (unsigned char)((v[0] << 4) | v[1]);
+}
+
+/*
+ * Check checksum of file denoted by filename. The expected hash value
+ * is given in hex_hash which is hex-encoded string.
+ *
+ * This function returns 1 if it succeeds or one of the following
+ * integers:
+ *
+ * 0:
+ * Checksum didn't match.
+ * -1:
+ * Could not open file; or could not read data from file.
+ * -2:
+ * Hash algorithm not available.
+ */
+static int check_hash(const char *filename,
+ const metalink_digest_def *digest_def,
+ const unsigned char *digest, FILE *error)
+{
+ unsigned char *result;
+ digest_context *dctx;
+ int check_ok, flags, fd;
+
+ flags = O_RDONLY;
+#ifdef O_BINARY
+ /* O_BINARY is required in order to avoid binary EOF in text mode */
+ flags |= O_BINARY;
+#endif
+
+ fd = open(filename, flags);
+ if(fd == -1) {
+ fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
+ digest_def->hash_name, strerror(errno));
+ return -1;
+ }
+
+ dctx = Curl_digest_init(digest_def->dparams);
+ if(!dctx) {
+ fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
+ digest_def->hash_name, "failed to initialize hash algorithm");
+ close(fd);
+ return -2;
+ }
+
+ result = malloc(digest_def->dparams->digest_resultlen);
+ while(1) {
+ unsigned char buf[4096];
+ ssize_t len = read(fd, buf, sizeof(buf));
+ if(len == 0) {
+ break;
+ }
+ else if(len == -1) {
+ fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
+ digest_def->hash_name, strerror(errno));
+ Curl_digest_final(dctx, result);
+ close(fd);
+ return -1;
+ }
+ Curl_digest_update(dctx, buf, (unsigned int)len);
+ }
+ Curl_digest_final(dctx, result);
+ check_ok = memcmp(result, digest,
+ digest_def->dparams->digest_resultlen) == 0;
+ /* sha*sum style verdict output */
+ if(check_ok)
+ fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
+ digest_def->hash_name);
+ else
+ fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
+ filename, digest_def->hash_name);
+
+ free(result);
+ close(fd);
+ return check_ok;
+}
+
+int metalink_check_hash(struct Configurable *config,
+ metalinkfile *mlfile,
+ const char *filename)
+{
+ int rv;
+ fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
+ if(mlfile->checksum == NULL) {
+ fprintf(config->errors,
+ "Metalink: validating (%s) FAILED (digest missing)\n",
+ filename);
+ return -2;
+ }
+ rv = check_hash(filename, mlfile->checksum->digest_def,
+ mlfile->checksum->digest, config->errors);
+ return rv;
+}
+
+static metalink_checksum *new_metalink_checksum_from_hex_digest
+(const metalink_digest_def *digest_def, const char *hex_digest)
+{
+ metalink_checksum *chksum;
+ unsigned char *digest;
+ size_t i;
+ size_t len = strlen(hex_digest);
+ digest = malloc(len/2);
+ for(i = 0; i < len; i += 2) {
+ digest[i/2] = hex_to_uint(hex_digest+i);
+ }
+ chksum = malloc(sizeof(metalink_checksum));
+ chksum->digest_def = digest_def;
+ chksum->digest = digest;
+ return chksum;
+}
+
+static metalink_resource *new_metalink_resource(const char *url)
+{
+ metalink_resource *res;
+ res = malloc(sizeof(metalink_resource));
+ res->next = NULL;
+ res->url = strdup(url);
+ return res;
+}
+
+/* Returns nonzero if hex_digest is properly formatted; that is each
+ letter is in [0-9A-Za-z] and the length of the string equals to the
+ result length of digest * 2. */
+static int check_hex_digest(const char *hex_digest,
+ const metalink_digest_def *digest_def)
+{
+ size_t i;
+ for(i = 0; hex_digest[i]; ++i) {
+ char c = hex_digest[i];
+ if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z'))) {
+ return 0;
+ }
+ }
+ return digest_def->dparams->digest_resultlen * 2 == i;
+}
+
+static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
+{
+ metalinkfile *f;
+ f = (metalinkfile*)malloc(sizeof(metalinkfile));
+ f->next = NULL;
+ f->filename = strdup(fileinfo->name);
+ f->checksum = NULL;
+ f->resource = NULL;
+ if(fileinfo->checksums) {
+ const metalink_digest_alias *digest_alias;
+ for(digest_alias = digest_aliases; digest_alias->alias_name;
+ ++digest_alias) {
+ metalink_checksum_t **p;
+ for(p = fileinfo->checksums; *p; ++p) {
+ if(Curl_raw_equal(digest_alias->alias_name, (*p)->type) &&
+ check_hex_digest((*p)->hash, digest_alias->digest_def)) {
+ f->checksum =
+ new_metalink_checksum_from_hex_digest(digest_alias->digest_def,
+ (*p)->hash);
+ break;
+ }
+ }
+ if(f->checksum) {
+ break;
+ }
+ }
+ }
+ if(fileinfo->resources) {
+ metalink_resource_t **p;
+ metalink_resource root, *tail;
+ root.next = NULL;
+ tail = &root;
+ for(p = fileinfo->resources; *p; ++p) {
+ metalink_resource *res;
+ /* Filter by type if it is non-NULL. In Metalink v3, type
+ includes the type of the resource. In curl, we are only
+ interested in HTTP, HTTPS and FTP. In addition to them,
+ Metalink v3 file may contain bittorrent type URL, which
+ points to the BitTorrent metainfo file. We ignore it here.
+ In Metalink v4, type was deprecated and all
+ fileinfo->resources point to the target file. BitTorrent
+ metainfo file URL may be appeared in fileinfo->metaurls.
+ */
+ if((*p)->type == NULL ||
+ Curl_raw_equal((*p)->type, "http") ||
+ Curl_raw_equal((*p)->type, "https") ||
+ Curl_raw_equal((*p)->type, "ftp") ||
+ Curl_raw_equal((*p)->type, "ftps")) {
+ res = new_metalink_resource((*p)->url);
+ tail->next = res;
+ tail = res;
+ }
+ }
+ f->resource = root.next;
+ }
+ return f;
+}
+
+int parse_metalink(struct Configurable *config, struct OutStruct *outs,
+ const char *metalink_url)
+{
+ metalink_error_t r;
+ metalink_t* metalink;
+ metalink_file_t **files;
+ bool warnings = FALSE;
+
+ /* metlaink_parse_final deletes outs->metalink_parser */
+ r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
+ outs->metalink_parser = NULL;
+ if(r != 0) {
+ return -1;
+ }
+ if(metalink->files == NULL) {
+ fprintf(config->errors, "Metalink: parsing (%s) WARNING "
+ "(missing or invalid file name)\n",
+ metalink_url);
+ metalink_delete(metalink);
+ return -1;
+ }
+ for(files = metalink->files; *files; ++files) {
+ struct getout *url;
+ /* Skip an entry which has no resource. */
+ if(!(*files)->resources) {
+ fprintf(config->errors, "Metalink: parsing (%s) WARNING "
+ "(missing or invalid resource)\n",
+ metalink_url, (*files)->name);
+ continue;
+ }
+ if(config->url_get ||
+ ((config->url_get = config->url_list) != NULL)) {
+ /* there's a node here, if it already is filled-in continue to
+ find an "empty" node */
+ while(config->url_get && (config->url_get->flags & GETOUT_URL))
+ config->url_get = config->url_get->next;
+ }
+
+ /* now there might or might not be an available node to fill in! */
+
+ if(config->url_get)
+ /* existing node */
+ url = config->url_get;
+ else
+ /* there was no free node, create one! */
+ url = new_getout(config);
+
+ if(url) {
+ metalinkfile *mlfile;
+ mlfile = new_metalinkfile(*files);
+ if(!mlfile->checksum) {
+ warnings = TRUE;
+ fprintf(config->errors, "Metalink: parsing (%s) WARNING "
+ "(digest missing)\n",
+ metalink_url);
+ }
+ /* Set name as url */
+ GetStr(&url->url, mlfile->filename);
+
+ /* set flag metalink here */
+ url->flags |= GETOUT_URL | GETOUT_METALINK;
+
+ if(config->metalinkfile_list) {
+ config->metalinkfile_last->next = mlfile;
+ config->metalinkfile_last = mlfile;
+ }
+ else {
+ config->metalinkfile_list = config->metalinkfile_last = mlfile;
+ }
+ }
+ }
+ metalink_delete(metalink);
+ return (warnings) ? -2 : 0;
+}
+
+size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
+ void *userdata)
+{
+ struct OutStruct *outs = userdata;
+ struct Configurable *config = outs->config;
+ int rv;
+
+ /*
+ * Once that libcurl has called back tool_write_cb() the returned value
+ * is checked against the amount that was intended to be written, if
+ * it does not match then it fails with CURLE_WRITE_ERROR. So at this
+ * point returning a value different from sz*nmemb indicates failure.
+ */
+ const size_t failure = (sz * nmemb) ? 0 : 1;
+
+ if(!config)
+ return failure;
+
+ rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb);
+ if(rv == 0)
+ return sz * nmemb;
+ else {
+ fprintf(config->errors, "Metalink: parsing FAILED\n");
+ return failure;
+ }
+}
+
+/*
+ * Returns nonzero if content_type includes mediatype.
+ */
+static int check_content_type(const char *content_type, const char *media_type)
+{
+ const char *ptr = content_type;
+ size_t media_type_len = strlen(media_type);
+ for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
+ if(!*ptr) {
+ return 0;
+ }
+ return Curl_raw_nequal(ptr, media_type, media_type_len) &&
+ (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' ||
+ *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';');
+}
+
+int check_metalink_content_type(const char *content_type)
+{
+ return check_content_type(content_type, "application/metalink+xml");
+}
+
+int count_next_metalink_resource(metalinkfile *mlfile)
+{
+ int count = 0;
+ metalink_resource *res;
+ for(res = mlfile->resource; res; res = res->next, ++count);
+ return count;
+}
+
+static void delete_metalink_checksum(metalink_checksum *chksum)
+{
+ if(chksum == NULL) {
+ return;
+ }
+ Curl_safefree(chksum->digest);
+ Curl_safefree(chksum);
+}
+
+static void delete_metalink_resource(metalink_resource *res)
+{
+ if(res == NULL) {
+ return;
+ }
+ Curl_safefree(res->url);
+ Curl_safefree(res);
+}
+
+static void delete_metalinkfile(metalinkfile *mlfile)
+{
+ metalink_resource *res;
+ if(mlfile == NULL) {
+ return;
+ }
+ Curl_safefree(mlfile->filename);
+ delete_metalink_checksum(mlfile->checksum);
+ for(res = mlfile->resource; res;) {
+ metalink_resource *next;
+ next = res->next;
+ delete_metalink_resource(res);
+ res = next;
+ }
+ Curl_safefree(mlfile);
+}
+
+void clean_metalink(struct Configurable *config)
+{
+ while(config->metalinkfile_list) {
+ metalinkfile *mlfile = config->metalinkfile_list;
+ config->metalinkfile_list = config->metalinkfile_list->next;
+ delete_metalinkfile(mlfile);
+ }
+ config->metalinkfile_last = 0;
+}
+
+void metalink_cleanup(void)
+{
+#if defined(USE_NSS) && defined(HAVE_NSS_INITCONTEXT)
+ if(nss_context) {
+ NSS_ShutdownContext(nss_context);
+ nss_context = NULL;
+ }
+#endif
+}
+
+#endif /* USE_METALINK */
diff --git a/src/tool_metalink.h b/src/tool_metalink.h
new file mode 100644
index 000000000..0a69c459e
--- /dev/null
+++ b/src/tool_metalink.h
@@ -0,0 +1,161 @@
+#ifndef HEADER_CURL_TOOL_METALINK_H
+#define HEADER_CURL_TOOL_METALINK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+/* returns 1 for success, 0 otherwise (we use OpenSSL *_Init fncs directly) */
+typedef int (* Curl_digest_init_func)(void *context);
+
+typedef void (* Curl_digest_update_func)(void *context,
+ const unsigned char *data,
+ unsigned int len);
+typedef void (* Curl_digest_final_func)(unsigned char *result, void *context);
+
+typedef struct {
+ Curl_digest_init_func digest_init; /* Initialize context procedure */
+ Curl_digest_update_func digest_update; /* Update context with data */
+ Curl_digest_final_func digest_final; /* Get final result procedure */
+ unsigned int digest_ctxtsize; /* Context structure size */
+ unsigned int digest_resultlen; /* Result length (bytes) */
+} digest_params;
+
+typedef struct {
+ const digest_params *digest_hash; /* Hash function definition */
+ void *digest_hashctx; /* Hash function context */
+} digest_context;
+
+digest_context * Curl_digest_init(const digest_params *dparams);
+int Curl_digest_update(digest_context *context,
+ const unsigned char *data,
+ unsigned int len);
+int Curl_digest_final(digest_context *context, unsigned char *result);
+
+typedef struct {
+ const char *hash_name;
+ const digest_params *dparams;
+} metalink_digest_def;
+
+typedef struct {
+ const char *alias_name;
+ const metalink_digest_def *digest_def;
+} metalink_digest_alias;
+
+typedef struct metalink_checksum {
+ const metalink_digest_def *digest_def;
+ /* raw digest value, not ascii hex digest */
+ unsigned char *digest;
+} metalink_checksum;
+
+typedef struct metalink_resource {
+ struct metalink_resource *next;
+ char *url;
+} metalink_resource;
+
+typedef struct metalinkfile {
+ struct metalinkfile *next;
+ char *filename;
+ metalink_checksum *checksum;
+ metalink_resource *resource;
+} metalinkfile;
+
+#ifdef USE_METALINK
+
+/*
+ * curl requires libmetalink 0.1.0 or newer
+ */
+#define CURL_REQ_LIBMETALINK_MAJOR 0
+#define CURL_REQ_LIBMETALINK_MINOR 1
+#define CURL_REQ_LIBMETALINK_PATCH 0
+
+#define CURL_REQ_LIBMETALINK_VERS ((CURL_REQ_LIBMETALINK_MAJOR * 10000) + \
+ (CURL_REQ_LIBMETALINK_MINOR * 100) + \
+ CURL_REQ_LIBMETALINK_PATCH)
+
+extern const digest_params MD5_DIGEST_PARAMS[1];
+extern const digest_params SHA1_DIGEST_PARAMS[1];
+extern const digest_params SHA256_DIGEST_PARAMS[1];
+
+#include <metalink/metalink.h>
+
+/*
+ * Counts the resource in the metalinkfile.
+ */
+int count_next_metalink_resource(metalinkfile *mlfile);
+void clean_metalink(struct Configurable *config);
+
+/*
+ * Performs final parse operation and extracts information from
+ * Metalink and creates metalinkfile structs.
+ *
+ * This function returns 0 if it succeeds without warnings, or one of
+ * the following negative error codes:
+ *
+ * -1: Parsing failed; or no file is found
+ * -2: Parsing succeeded with some warnings.
+ */
+int parse_metalink(struct Configurable *config, struct OutStruct *outs,
+ const char *metalink_url);
+
+/*
+ * Callback function for CURLOPT_WRITEFUNCTION
+ */
+size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
+ void *userdata);
+
+/*
+ * Returns nonzero if content_type includes "application/metalink+xml"
+ * media-type. The check is done in case-insensitive manner.
+ */
+int check_metalink_content_type(const char *content_type);
+
+/*
+ * Check checksum of file denoted by filename.
+ *
+ * This function returns 1 if the checksum matches or one of the
+ * following integers:
+ *
+ * 0:
+ * Checksum didn't match.
+ * -1:
+ * Could not open file; or could not read data from file.
+ * -2:
+ * No checksum in Metalink supported, hash algorithm not available, or
+ * Metalink does not contain checksum.
+ */
+int metalink_check_hash(struct Configurable *config,
+ metalinkfile *mlfile,
+ const char *filename);
+
+/*
+ * Release resources allocated at global scope.
+ */
+void metalink_cleanup(void);
+
+#else /* USE_METALINK */
+
+#define count_next_metalink_resource(x) 0
+#define clean_metalink(x) Curl_nop_stmt
+
+#endif /* USE_METALINK */
+
+#endif /* HEADER_CURL_TOOL_METALINK_H */
diff --git a/src/tool_mfiles.c b/src/tool_mfiles.c
new file mode 100644
index 000000000..3eda45f91
--- /dev/null
+++ b/src/tool_mfiles.c
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "tool_mfiles.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+static void AppendNode(struct multi_files **first,
+ struct multi_files **last,
+ struct multi_files *new)
+{
+ DEBUGASSERT(((*first) && (*last)) || ((!*first) && (!*last)));
+
+ if(*last)
+ (*last)->next = new;
+ else
+ *first = new;
+ *last = new;
+}
+
+/*
+ * AddMultiFiles: Add a new list node possibly followed with a type_name.
+ *
+ * multi_first argument is the address of a pointer to the first element
+ * of the multi_files linked list. A NULL pointer indicates empty list.
+ *
+ * multi_last argument is the address of a pointer to the last element
+ * of the multi_files linked list. A NULL pointer indicates empty list.
+ *
+ * Pointers stored in multi_first and multi_last are modified while
+ * function is executed. An out of memory condition free's the whole
+ * list and returns with pointers stored in multi_first and multi_last
+ * set to NULL and a NULL function result.
+ *
+ * Function returns same pointer as stored at multi_last.
+ */
+
+struct multi_files *AddMultiFiles(const char *file_name,
+ const char *type_name,
+ const char *show_filename,
+ struct multi_files **multi_first,
+ struct multi_files **multi_last)
+{
+ struct multi_files *multi;
+ struct multi_files *multi_type;
+ struct multi_files *multi_name;
+
+ multi = calloc(1, sizeof(struct multi_files));
+ if(multi) {
+ multi->form.option = CURLFORM_FILE;
+ multi->form.value = file_name;
+ AppendNode(multi_first, multi_last, multi);
+ }
+ else {
+ FreeMultiInfo(multi_first, multi_last);
+ return NULL;
+ }
+
+ if(type_name) {
+ multi_type = calloc(1, sizeof(struct multi_files));
+ if(multi_type) {
+ multi_type->form.option = CURLFORM_CONTENTTYPE;
+ multi_type->form.value = type_name;
+ AppendNode(multi_first, multi_last, multi_type);
+ }
+ else {
+ FreeMultiInfo(multi_first, multi_last);
+ return NULL;
+ }
+ }
+
+ if(show_filename) {
+ multi_name = calloc(1, sizeof(struct multi_files));
+ if(multi_name) {
+ multi_name->form.option = CURLFORM_FILENAME;
+ multi_name->form.value = show_filename;
+ AppendNode(multi_first, multi_last, multi_name);
+ }
+ else {
+ FreeMultiInfo(multi_first, multi_last);
+ return NULL;
+ }
+ }
+
+ return *multi_last;
+}
+
+/*
+ * FreeMultiInfo: Free the items of the list.
+ */
+
+void FreeMultiInfo(struct multi_files **multi_first,
+ struct multi_files **multi_last)
+{
+ struct multi_files *next;
+ struct multi_files *item = *multi_first;
+
+ while(item) {
+ next = item->next;
+ Curl_safefree(item);
+ item = next;
+ }
+ *multi_first = NULL;
+ if(multi_last)
+ *multi_last = NULL;
+}
+
diff --git a/src/tool_mfiles.h b/src/tool_mfiles.h
new file mode 100644
index 000000000..1ea6f4a47
--- /dev/null
+++ b/src/tool_mfiles.h
@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_TOOL_MFILES_H
+#define HEADER_CURL_TOOL_MFILES_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+/*
+ * Structure for storing the information needed to build
+ * a multiple files section.
+ */
+
+struct multi_files {
+ struct curl_forms form;
+ struct multi_files *next;
+};
+
+struct multi_files *AddMultiFiles(const char *file_name,
+ const char *type_name,
+ const char *show_filename,
+ struct multi_files **multi_first,
+ struct multi_files **multi_last);
+
+void FreeMultiInfo(struct multi_files **multi_first,
+ struct multi_files **multi_last);
+
+#endif /* HEADER_CURL_TOOL_MFILES_H */
+
diff --git a/src/tool_msgs.c b/src/tool_msgs.c
new file mode 100644
index 000000000..80fdf4e27
--- /dev/null
+++ b/src/tool_msgs.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_msgs.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#define WARN_PREFIX "Warning: "
+#define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX))
+
+/*
+ * Emit warning formatted message on configured 'errors' stream unless
+ * mute (--silent) was selected.
+ */
+
+void warnf(struct Configurable *config, const char *fmt, ...)
+{
+ if(!config->mute) {
+ va_list ap;
+ int len;
+ char *ptr;
+ char print_buffer[256];
+
+ va_start(ap, fmt);
+ len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
+ va_end(ap);
+
+ ptr = print_buffer;
+ while(len > 0) {
+ fputs(WARN_PREFIX, config->errors);
+
+ if(len > (int)WARN_TEXTWIDTH) {
+ int cut = WARN_TEXTWIDTH-1;
+
+ while(!ISSPACE(ptr[cut]) && cut) {
+ cut--;
+ }
+ if(0 == cut)
+ /* not a single cutting position was found, just cut it at the
+ max text width then! */
+ cut = WARN_TEXTWIDTH-1;
+
+ (void)fwrite(ptr, cut + 1, 1, config->errors);
+ fputs("\n", config->errors);
+ ptr += cut+1; /* skip the space too */
+ len -= cut;
+ }
+ else {
+ fputs(ptr, config->errors);
+ len = 0;
+ }
+ }
+ }
+}
+
+/*
+ * Emit help formatted message on given stream.
+ */
+
+void helpf(FILE *errors, const char *fmt, ...)
+{
+ va_list ap;
+ if(fmt) {
+ va_start(ap, fmt);
+ fputs("curl: ", errors); /* prefix it */
+ vfprintf(errors, fmt, ap);
+ va_end(ap);
+ }
+ fprintf(errors, "curl: try 'curl --help' "
+#ifdef USE_MANUAL
+ "or 'curl --manual' "
+#endif
+ "for more information\n");
+}
+
diff --git a/src/tool_msgs.h b/src/tool_msgs.h
new file mode 100644
index 000000000..7b060894f
--- /dev/null
+++ b/src/tool_msgs.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_TOOL_MSGS_H
+#define HEADER_CURL_TOOL_MSGS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+void warnf(struct Configurable *config, const char *fmt, ...);
+
+void helpf(FILE *errors, const char *fmt, ...);
+
+#endif /* HEADER_CURL_TOOL_MSGS_H */
+
diff --git a/src/tool_operate.c b/src/tool_operate.c
new file mode 100644
index 000000000..826b4a5da
--- /dev/null
+++ b/src/tool_operate.c
@@ -0,0 +1,1783 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#elif defined(HAVE_SYS_UTIME_H)
+# include <sys/utime.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+#endif
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_binmode.h"
+#include "tool_cfgable.h"
+#include "tool_cb_dbg.h"
+#include "tool_cb_hdr.h"
+#include "tool_cb_prg.h"
+#include "tool_cb_rea.h"
+#include "tool_cb_see.h"
+#include "tool_cb_wrt.h"
+#include "tool_dirhie.h"
+#include "tool_doswin.h"
+#include "tool_easysrc.h"
+#include "tool_getparam.h"
+#include "tool_helpers.h"
+#include "tool_homedir.h"
+#include "tool_libinfo.h"
+#include "tool_main.h"
+#include "tool_metalink.h"
+#include "tool_msgs.h"
+#include "tool_operate.h"
+#include "tool_operhlp.h"
+#include "tool_parsecfg.h"
+#include "tool_setopt.h"
+#include "tool_sleep.h"
+#include "tool_urlglob.h"
+#include "tool_util.h"
+#include "tool_writeenv.h"
+#include "tool_writeout.h"
+#include "tool_xattr.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#define CURLseparator "--_curl_--"
+
+#ifndef O_BINARY
+/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
+ source code but yet it doesn't ruin anything */
+# define O_BINARY 0
+#endif
+
+#define CURL_CA_CERT_ERRORMSG1 \
+ "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
+ "curl performs SSL certificate verification by default, " \
+ "using a \"bundle\"\n" \
+ " of Certificate Authority (CA) public keys (CA certs). If the default\n" \
+ " bundle file isn't adequate, you can specify an alternate file\n" \
+ " using the --cacert option.\n"
+
+#define CURL_CA_CERT_ERRORMSG2 \
+ "If this HTTPS server uses a certificate signed by a CA represented in\n" \
+ " the bundle, the certificate verification probably failed due to a\n" \
+ " problem with the certificate (it might be expired, or the name might\n" \
+ " not match the domain name in the URL).\n" \
+ "If you'd like to turn off curl's verification of the certificate, use\n" \
+ " the -k (or --insecure) option.\n"
+
+static int is_fatal_error(int code)
+{
+ switch(code) {
+ /* TODO: Should CURLE_SSL_CACERT be included as critical error ? */
+ case CURLE_FAILED_INIT:
+ case CURLE_OUT_OF_MEMORY:
+ case CURLE_UNKNOWN_OPTION:
+ case CURLE_FUNCTION_NOT_FOUND:
+ case CURLE_BAD_FUNCTION_ARGUMENT:
+ /* critical error */
+ return 1;
+ default:
+ break;
+ }
+ /* no error or not critical */
+ return 0;
+}
+
+int operate(struct Configurable *config, int argc, argv_item_t argv[])
+{
+ char errorbuffer[CURL_ERROR_SIZE];
+ struct ProgressData progressbar;
+ struct getout *urlnode;
+
+ struct HdrCbData hdrcbdata;
+ struct OutStruct heads;
+
+ metalinkfile *mlfile_last = NULL;
+
+ CURL *curl = NULL;
+ char *httpgetfields = NULL;
+
+ bool stillflags;
+ int res = 0;
+ int i;
+
+ bool orig_noprogress;
+ bool orig_isatty;
+
+ errorbuffer[0] = '\0';
+ /* default headers output stream is stdout */
+ memset(&hdrcbdata, 0, sizeof(struct HdrCbData));
+ memset(&heads, 0, sizeof(struct OutStruct));
+ heads.stream = stdout;
+ heads.config = config;
+
+ memory_tracking_init();
+
+ /*
+ ** Initialize curl library - do not call any libcurl functions before
+ ** this point. Note that the memory_tracking_init() magic above is an
+ ** exception, but then that's not part of the official public API.
+ */
+ if(main_init() != CURLE_OK) {
+ helpf(config->errors, "error initializing curl library\n");
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Get libcurl info right away */
+ if(get_libcurl_info() != CURLE_OK) {
+ helpf(config->errors, "error retrieving curl library information\n");
+ main_free();
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Get a curl handle to use for all forthcoming curl transfers */
+ curl = curl_easy_init();
+ if(!curl) {
+ helpf(config->errors, "error initializing curl easy handle\n");
+ main_free();
+ return CURLE_FAILED_INIT;
+ }
+ config->easy = curl;
+
+ /*
+ ** Beyond this point no return'ing from this function allowed.
+ ** Jump to label 'quit_curl' in order to abandon this function
+ ** from outside of nested loops further down below.
+ */
+
+ /* setup proper locale from environment */
+#ifdef HAVE_SETLOCALE
+ setlocale(LC_ALL, "");
+#endif
+
+ /* inits */
+ config->postfieldsize = -1;
+ config->showerror = -1; /* will show errors */
+ config->use_httpget = FALSE;
+ config->create_dirs = FALSE;
+ config->maxredirs = DEFAULT_MAXREDIRS;
+ config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */
+ config->proto_present = FALSE;
+ config->proto_redir =
+ CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
+ config->proto_redir_present = FALSE;
+
+ if((argc > 1) &&
+ (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
+ strchr(argv[1], 'q')) {
+ /*
+ * The first flag, that is not a verbose name, but a shortname
+ * and it includes the 'q' flag!
+ */
+ ;
+ }
+ else {
+ parseconfig(NULL, config); /* ignore possible failure */
+ }
+
+ if((argc < 2) && !config->url_list) {
+ helpf(config->errors, NULL);
+ res = CURLE_FAILED_INIT;
+ goto quit_curl;
+ }
+
+ /* Parse options */
+ for(i = 1, stillflags = TRUE; i < argc; i++) {
+ if(stillflags &&
+ ('-' == argv[i][0])) {
+ char *nextarg;
+ bool passarg;
+ char *orig_opt = argv[i];
+
+ char *flag = argv[i];
+
+ if(curlx_strequal("--", argv[i]))
+ /* this indicates the end of the flags and thus enables the
+ following (URL) argument to start with -. */
+ stillflags = FALSE;
+ else {
+ nextarg = (i < (argc-1)) ? argv[i+1] : NULL;
+
+ res = getparameter(flag, nextarg, &passarg, config);
+ if(res) {
+ int retval = CURLE_OK;
+ if(res != PARAM_HELP_REQUESTED) {
+ const char *reason = param2text(res);
+ helpf(config->errors, "option %s: %s\n", orig_opt, reason);
+ retval = CURLE_FAILED_INIT;
+ }
+ res = retval;
+ goto quit_curl;
+ }
+
+ if(passarg) /* we're supposed to skip this */
+ i++;
+ }
+ }
+ else {
+ bool used;
+ /* just add the URL please */
+ res = getparameter((char *)"--url", argv[i], &used, config);
+ if(res)
+ goto quit_curl;
+ }
+ }
+
+ if((!config->url_list || !config->url_list->url) && !config->list_engines) {
+ helpf(config->errors, "no URL specified!\n");
+ res = CURLE_FAILED_INIT;
+ goto quit_curl;
+ }
+
+ if(!config->useragent)
+ config->useragent = my_useragent();
+ if(!config->useragent) {
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+
+ /* On WIN32 we can't set the path to curl-ca-bundle.crt
+ * at compile time. So we look here for the file in two ways:
+ * 1: look at the environment variable CURL_CA_BUNDLE for a path
+ * 2: if #1 isn't found, use the windows API function SearchPath()
+ * to find it along the app's path (includes app's dir and CWD)
+ *
+ * We support the environment variable thing for non-Windows platforms
+ * too. Just for the sake of it.
+ */
+ if(!config->cacert &&
+ !config->capath &&
+ !config->insecure_ok) {
+ char *env;
+ env = curlx_getenv("CURL_CA_BUNDLE");
+ if(env) {
+ config->cacert = strdup(env);
+ if(!config->cacert) {
+ curl_free(env);
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+ }
+ else {
+ env = curlx_getenv("SSL_CERT_DIR");
+ if(env) {
+ config->capath = strdup(env);
+ if(!config->capath) {
+ curl_free(env);
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+ }
+ else {
+ env = curlx_getenv("SSL_CERT_FILE");
+ if(env) {
+ config->cacert = strdup(env);
+ if(!config->cacert) {
+ curl_free(env);
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+ }
+ }
+ }
+
+ if(env)
+ curl_free(env);
+#ifdef WIN32
+ else {
+ res = FindWin32CACert(config, "curl-ca-bundle.crt");
+ if(res)
+ goto quit_curl;
+ }
+#endif
+ }
+
+ if(config->postfields) {
+ if(config->use_httpget) {
+ /* Use the postfields data for a http get */
+ httpgetfields = strdup(config->postfields);
+ Curl_safefree(config->postfields);
+ if(!httpgetfields) {
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ goto quit_curl;
+ }
+ if(SetHTTPrequest(config,
+ (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
+ &config->httpreq)) {
+ res = PARAM_BAD_USE;
+ goto quit_curl;
+ }
+ }
+ else {
+ if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) {
+ res = PARAM_BAD_USE;
+ goto quit_curl;
+ }
+ }
+ }
+
+#ifndef CURL_DISABLE_LIBCURL_OPTION
+ res = easysrc_init();
+ if(res) {
+ helpf(config->errors, "out of memory\n");
+ goto quit_curl;
+ }
+#endif
+
+ if(config->list_engines) {
+ struct curl_slist *engines = NULL;
+ curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
+ list_engines(engines);
+ curl_slist_free_all(engines);
+ res = CURLE_OK;
+ goto quit_curl;
+ }
+
+ /* Single header file for all URLs */
+ if(config->headerfile) {
+ /* open file for output: */
+ if(!curlx_strequal(config->headerfile, "-")) {
+ FILE *newfile = fopen(config->headerfile, "wb");
+ if(!newfile) {
+ warnf(config, "Failed to open %s\n", config->headerfile);
+ res = CURLE_WRITE_ERROR;
+ goto quit_curl;
+ }
+ else {
+ heads.filename = config->headerfile;
+ heads.s_isreg = TRUE;
+ heads.fopened = TRUE;
+ heads.stream = newfile;
+ }
+ }
+ }
+
+ /* save the values of noprogress and isatty to restore them later on */
+ orig_noprogress = config->noprogress;
+ orig_isatty = config->isatty;
+
+ /*
+ ** Nested loops start here.
+ */
+
+ /* loop through the list of given URLs */
+
+ for(urlnode = config->url_list; urlnode; urlnode = urlnode->next) {
+
+ int up; /* upload file counter within a single upload glob */
+ char *infiles; /* might be a glob pattern */
+ char *outfiles;
+ int infilenum;
+ URLGlob *inglob;
+
+ int metalink = 0; /* nonzero for metalink download. */
+ metalinkfile *mlfile;
+ metalink_resource *mlres;
+
+ outfiles = NULL;
+ infilenum = 1;
+ inglob = NULL;
+
+ if(urlnode->flags & GETOUT_METALINK) {
+ metalink = 1;
+ if(mlfile_last == NULL) {
+ mlfile_last = config->metalinkfile_list;
+ }
+ mlfile = mlfile_last;
+ mlfile_last = mlfile_last->next;
+ mlres = mlfile->resource;
+ }
+ else {
+ mlfile = NULL;
+ mlres = NULL;
+ }
+
+ /* urlnode->url is the full URL (it might be NULL) */
+
+ if(!urlnode->url) {
+ /* This node has no URL. Free node data without destroying the
+ node itself nor modifying next pointer and continue to next */
+ Curl_safefree(urlnode->outfile);
+ Curl_safefree(urlnode->infile);
+ urlnode->flags = 0;
+ continue; /* next URL please */
+ }
+
+ /* save outfile pattern before expansion */
+ if(urlnode->outfile) {
+ outfiles = strdup(urlnode->outfile);
+ if(!outfiles) {
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ }
+
+ infiles = urlnode->infile;
+
+ if(!config->globoff && infiles) {
+ /* Unless explicitly shut off */
+ res = glob_url(&inglob, infiles, &infilenum,
+ config->showerror?config->errors:NULL);
+ if(res) {
+ Curl_safefree(outfiles);
+ break;
+ }
+ }
+
+ /* Here's the loop for uploading multiple files within the same
+ single globbed string. If no upload, we enter the loop once anyway. */
+ for(up = 0 ; up < infilenum; up++) {
+
+ char *uploadfile; /* a single file, never a glob */
+ int separator;
+ URLGlob *urls;
+ int urlnum;
+
+ uploadfile = NULL;
+ urls = NULL;
+ urlnum = 0;
+
+ if(!up && !infiles)
+ Curl_nop_stmt;
+ else {
+ if(inglob) {
+ res = glob_next_url(&uploadfile, inglob);
+ if(res == CURLE_OUT_OF_MEMORY)
+ helpf(config->errors, "out of memory\n");
+ }
+ else if(!up) {
+ uploadfile = strdup(infiles);
+ if(!uploadfile) {
+ helpf(config->errors, "out of memory\n");
+ res = CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else
+ uploadfile = NULL;
+ if(!uploadfile)
+ break;
+ }
+
+ if(metalink) {
+ /* For Metalink download, we don't use glob. Instead we use
+ the number of resources as urlnum. */
+ urlnum = count_next_metalink_resource(mlfile);
+ }
+ else
+ if(!config->globoff) {
+ /* Unless explicitly shut off, we expand '{...}' and '[...]'
+ expressions and return total number of URLs in pattern set */
+ res = glob_url(&urls, urlnode->url, &urlnum,
+ config->showerror?config->errors:NULL);
+ if(res) {
+ Curl_safefree(uploadfile);
+ break;
+ }
+ }
+ else
+ urlnum = 1; /* without globbing, this is a single URL */
+
+ /* if multiple files extracted to stdout, insert separators! */
+ separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
+
+ /* Here's looping around each globbed URL */
+ for(i = 0 ; i < urlnum; i++) {
+
+ int infd;
+ bool infdopen;
+ char *outfile;
+ struct OutStruct outs;
+ struct InStruct input;
+ struct timeval retrystart;
+ curl_off_t uploadfilesize;
+ long retry_numretries;
+ long retry_sleep_default;
+ long retry_sleep;
+ char *this_url;
+ int metalink_next_res = 0;
+
+ outfile = NULL;
+ infdopen = FALSE;
+ infd = STDIN_FILENO;
+ uploadfilesize = -1; /* -1 means unknown */
+
+ /* default output stream is stdout */
+ memset(&outs, 0, sizeof(struct OutStruct));
+ outs.stream = stdout;
+ outs.config = config;
+
+ if(metalink) {
+ /* For Metalink download, use name in Metalink file as
+ filename. */
+ outfile = strdup(mlfile->filename);
+ if(!outfile) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ this_url = strdup(mlres->url);
+ if(!this_url) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ }
+ else {
+ if(urls) {
+ res = glob_next_url(&this_url, urls);
+ if(res)
+ goto show_error;
+ }
+ else if(!i) {
+ this_url = strdup(urlnode->url);
+ if(!this_url) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ }
+ else
+ this_url = NULL;
+ if(!this_url)
+ break;
+
+ if(outfiles) {
+ outfile = strdup(outfiles);
+ if(!outfile) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ }
+ }
+
+ if(((urlnode->flags&GETOUT_USEREMOTE) ||
+ (outfile && !curlx_strequal("-", outfile))) &&
+ (metalink || !config->use_metalink)) {
+
+ /*
+ * We have specified a file name to store the result in, or we have
+ * decided we want to use the remote file name.
+ */
+
+ if(!outfile) {
+ /* extract the file name from the URL */
+ res = get_url_file_name(&outfile, this_url);
+ if(res)
+ goto show_error;
+ if((!outfile || !*outfile) && !config->content_disposition) {
+ helpf(config->errors, "Remote file name has no length!\n");
+ res = CURLE_WRITE_ERROR;
+ goto quit_urls;
+ }
+#if defined(MSDOS) || defined(WIN32)
+ /* For DOS and WIN32, we do some major replacing of
+ bad characters in the file name before using it */
+ outfile = sanitize_dos_name(outfile);
+ if(!outfile) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+#endif /* MSDOS || WIN32 */
+ }
+ else if(urls) {
+ /* fill '#1' ... '#9' terms from URL pattern */
+ char *storefile = outfile;
+ res = glob_match_url(&outfile, storefile, urls);
+ Curl_safefree(storefile);
+ if(res) {
+ /* bad globbing */
+ warnf(config, "bad output glob!\n");
+ goto quit_urls;
+ }
+ }
+
+ /* Create the directory hierarchy, if not pre-existent to a multiple
+ file output call */
+
+ if(config->create_dirs || metalink) {
+ res = create_dir_hierarchy(outfile, config->errors);
+ /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */
+ if(res == CURLE_WRITE_ERROR)
+ goto quit_urls;
+ if(res) {
+ goto show_error;
+ }
+ }
+
+ if((urlnode->flags & GETOUT_USEREMOTE)
+ && config->content_disposition) {
+ /* Our header callback MIGHT set the filename */
+ DEBUGASSERT(!outs.filename);
+ }
+
+ if(config->resume_from_current) {
+ /* We're told to continue from where we are now. Get the size
+ of the file as it is now and open it for append instead */
+ struct_stat fileinfo;
+ /* VMS -- Danger, the filesize is only valid for stream files */
+ if(0 == stat(outfile, &fileinfo))
+ /* set offset to current file size: */
+ config->resume_from = fileinfo.st_size;
+ else
+ /* let offset be 0 */
+ config->resume_from = 0;
+ }
+
+ if(config->resume_from) {
+ /* open file for output: */
+ FILE *file = fopen(outfile, config->resume_from?"ab":"wb");
+ if(!file) {
+ helpf(config->errors, "Can't open '%s'!\n", outfile);
+ res = CURLE_WRITE_ERROR;
+ goto quit_urls;
+ }
+ outs.fopened = TRUE;
+ outs.stream = file;
+ outs.init = config->resume_from;
+ }
+ else {
+ outs.stream = NULL; /* open when needed */
+ }
+ outs.filename = outfile;
+ outs.s_isreg = TRUE;
+ }
+
+ if(uploadfile && !stdin_upload(uploadfile)) {
+ /*
+ * We have specified a file to upload and it isn't "-".
+ */
+ struct_stat fileinfo;
+
+ this_url = add_file_name_to_url(curl, this_url, uploadfile);
+ if(!this_url) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ /* VMS Note:
+ *
+ * Reading binary from files can be a problem... Only FIXED, VAR
+ * etc WITHOUT implied CC will work Others need a \n appended to a
+ * line
+ *
+ * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
+ * fixed file with implied CC needs to have a byte added for every
+ * record processed, this can by derived from Filesize & recordsize
+ * for VARiable record files the records need to be counted! for
+ * every record add 1 for linefeed and subtract 2 for the record
+ * header for VARIABLE header files only the bare record data needs
+ * to be considered with one appended if implied CC
+ */
+
+ infd = open(uploadfile, O_RDONLY | O_BINARY);
+ if((infd == -1) || fstat(infd, &fileinfo)) {
+ helpf(config->errors, "Can't open '%s'!\n", uploadfile);
+ if(infd != -1) {
+ close(infd);
+ infd = STDIN_FILENO;
+ }
+ res = CURLE_READ_ERROR;
+ goto quit_urls;
+ }
+ infdopen = TRUE;
+
+ /* we ignore file size for char/block devices, sockets, etc. */
+ if(S_ISREG(fileinfo.st_mode))
+ uploadfilesize = fileinfo.st_size;
+
+ }
+ else if(uploadfile && stdin_upload(uploadfile)) {
+ /* count to see if there are more than one auth bit set
+ in the authtype field */
+ int authbits = 0;
+ int bitcheck = 0;
+ while(bitcheck < 32) {
+ if(config->authtype & (1UL << bitcheck++)) {
+ authbits++;
+ if(authbits > 1) {
+ /* more than one, we're done! */
+ break;
+ }
+ }
+ }
+
+ /*
+ * If the user has also selected --anyauth or --proxy-anyauth
+ * we should warn him/her.
+ */
+ if(config->proxyanyauth || (authbits>1)) {
+ warnf(config,
+ "Using --anyauth or --proxy-anyauth with upload from stdin"
+ " involves a big risk of it not working. Use a temporary"
+ " file or a fixed auth type instead!\n");
+ }
+
+ DEBUGASSERT(infdopen == FALSE);
+ DEBUGASSERT(infd == STDIN_FILENO);
+
+ set_binmode(stdin);
+ if(curlx_strequal(uploadfile, ".")) {
+ if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
+ warnf(config,
+ "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
+ }
+ }
+
+ if(uploadfile && config->resume_from_current)
+ config->resume_from = -1; /* -1 will then force get-it-yourself */
+
+ if(output_expected(this_url, uploadfile)
+ && outs.stream && isatty(fileno(outs.stream)))
+ /* we send the output to a tty, therefore we switch off the progress
+ meter */
+ config->noprogress = config->isatty = TRUE;
+ else {
+ /* progress meter is per download, so restore config
+ values */
+ config->noprogress = orig_noprogress;
+ config->isatty = orig_isatty;
+ }
+
+ if(urlnum > 1 && !(config->mute)) {
+ fprintf(config->errors, "\n[%d/%d]: %s --> %s\n",
+ i+1, urlnum, this_url, outfile ? outfile : "<stdout>");
+ if(separator)
+ printf("%s%s\n", CURLseparator, this_url);
+ }
+ if(httpgetfields) {
+ char *urlbuffer;
+ /* Find out whether the url contains a file name */
+ const char *pc = strstr(this_url, "://");
+ char sep = '?';
+ if(pc)
+ pc += 3;
+ else
+ pc = this_url;
+
+ pc = strrchr(pc, '/'); /* check for a slash */
+
+ if(pc) {
+ /* there is a slash present in the URL */
+
+ if(strchr(pc, '?'))
+ /* Ouch, there's already a question mark in the URL string, we
+ then append the data with an ampersand separator instead! */
+ sep='&';
+ }
+ /*
+ * Then append ? followed by the get fields to the url.
+ */
+ urlbuffer = malloc(strlen(this_url) + strlen(httpgetfields) + 3);
+ if(!urlbuffer) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ if(pc)
+ sprintf(urlbuffer, "%s%c%s", this_url, sep, httpgetfields);
+ else
+ /* Append / before the ? to create a well-formed url
+ if the url contains a hostname only
+ */
+ sprintf(urlbuffer, "%s/?%s", this_url, httpgetfields);
+
+ Curl_safefree(this_url); /* free previous URL */
+ this_url = urlbuffer; /* use our new URL instead! */
+ }
+
+ if(!config->errors)
+ config->errors = stderr;
+
+ if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
+ /* We get the output to stdout and we have not got the ASCII/text
+ flag, then set stdout to be binary */
+ set_binmode(stdout);
+ }
+
+ if(config->tcp_nodelay)
+ my_setopt(curl, CURLOPT_TCP_NODELAY, 1);
+
+ /* where to store */
+ my_setopt(curl, CURLOPT_WRITEDATA, &outs);
+ if(metalink || !config->use_metalink)
+ /* what call to write */
+ my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);
+#ifdef USE_METALINK
+ else
+ /* Set Metalink specific write callback function to parse
+ XML data progressively. */
+ my_setopt(curl, CURLOPT_WRITEFUNCTION, metalink_write_cb);
+#endif /* USE_METALINK */
+
+ /* for uploads */
+ input.fd = infd;
+ input.config = config;
+ /* Note that if CURLOPT_READFUNCTION is fread (the default), then
+ * lib/telnet.c will Curl_poll() on the input file descriptor
+ * rather then calling the READFUNCTION at regular intervals.
+ * The circumstances in which it is preferable to enable this
+ * behaviour, by omitting to set the READFUNCTION & READDATA options,
+ * have not been determined.
+ */
+ my_setopt(curl, CURLOPT_READDATA, &input);
+ /* what call to read */
+ my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb);
+
+ /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
+ CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
+ my_setopt(curl, CURLOPT_SEEKDATA, &input);
+ my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
+
+ if(config->recvpersecond)
+ /* tell libcurl to use a smaller sized buffer as it allows us to
+ make better sleeps! 7.9.9 stuff! */
+ my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
+
+ /* size of uploaded file: */
+ if(uploadfilesize != -1)
+ my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
+ my_setopt_str(curl, CURLOPT_URL, this_url); /* what to fetch */
+ my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress);
+ if(config->no_body) {
+ my_setopt(curl, CURLOPT_NOBODY, 1);
+ my_setopt(curl, CURLOPT_HEADER, 1);
+ }
+ /* If --metalink is used, we ignore --include (headers in
+ output) option because mixing headers to the body will
+ confuse XML parser and/or hash check will fail. */
+ else if(!config->use_metalink)
+ my_setopt(curl, CURLOPT_HEADER, config->include_headers);
+
+#if !defined(CURL_DISABLE_PROXY)
+ {
+ /* TODO: Make this a run-time check instead of compile-time one. */
+
+ my_setopt_str(curl, CURLOPT_PROXY, config->proxy);
+ my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
+
+ /* new in libcurl 7.3 */
+ my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
+
+ /* new in libcurl 7.5 */
+ if(config->proxy)
+ my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->proxyver);
+
+ /* new in libcurl 7.10 */
+ if(config->socksproxy) {
+ my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
+ my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->socksver);
+ }
+
+ /* new in libcurl 7.10.6 */
+ if(config->proxyanyauth)
+ my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
+ (long) CURLAUTH_ANY);
+ else if(config->proxynegotiate)
+ my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
+ (long) CURLAUTH_GSSNEGOTIATE);
+ else if(config->proxyntlm)
+ my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
+ (long) CURLAUTH_NTLM);
+ else if(config->proxydigest)
+ my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
+ (long) CURLAUTH_DIGEST);
+ else if(config->proxybasic)
+ my_setopt_bitmask(curl, CURLOPT_PROXYAUTH,
+ (long) CURLAUTH_BASIC);
+
+ /* new in libcurl 7.19.4 */
+ my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
+ }
+#endif
+
+ my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror);
+ my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
+ my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly);
+ my_setopt(curl, CURLOPT_APPEND, config->ftp_append);
+
+ if(config->netrc_opt)
+ my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
+ else if(config->netrc || config->netrc_file)
+ my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
+ else
+ my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
+
+ if(config->netrc_file)
+ my_setopt(curl, CURLOPT_NETRC_FILE, config->netrc_file);
+
+ my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
+ my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
+ my_setopt_str(curl, CURLOPT_RANGE, config->range);
+ my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
+ my_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
+
+ if(built_in_protos & CURLPROTO_HTTP) {
+
+ long postRedir = 0;
+
+ my_setopt(curl, CURLOPT_FOLLOWLOCATION,
+ config->followlocation);
+ my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH,
+ config->unrestricted_auth);
+
+ switch(config->httpreq) {
+ case HTTPREQ_SIMPLEPOST:
+ my_setopt_str(curl, CURLOPT_POSTFIELDS,
+ config->postfields);
+ my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
+ config->postfieldsize);
+ break;
+ case HTTPREQ_POST:
+ my_setopt_httppost(curl, CURLOPT_HTTPPOST, config->httppost);
+ break;
+ default:
+ break;
+ }
+
+ my_setopt_str(curl, CURLOPT_REFERER, config->referer);
+ my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer);
+ my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
+ my_setopt_slist(curl, CURLOPT_HTTPHEADER, config->headers);
+
+ /* new in libcurl 7.5 */
+ my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
+
+ /* new in libcurl 7.9.1 */
+ if(config->httpversion)
+ my_setopt_enum(curl, CURLOPT_HTTP_VERSION, config->httpversion);
+
+ /* new in libcurl 7.10.6 (default is Basic) */
+ if(config->authtype)
+ my_setopt_bitmask(curl, CURLOPT_HTTPAUTH, (long) config->authtype);
+
+ /* curl 7.19.1 (the 301 version existed in 7.18.2),
+ 303 was added in 7.26.0 */
+ if(config->post301)
+ postRedir |= CURL_REDIR_POST_301;
+ if(config->post302)
+ postRedir |= CURL_REDIR_POST_302;
+ if(config->post303)
+ postRedir |= CURL_REDIR_POST_303;
+ my_setopt(curl, CURLOPT_POSTREDIR, postRedir);
+
+ /* new in libcurl 7.21.6 */
+ if(config->encoding)
+ my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, "");
+
+ /* new in libcurl 7.21.6 */
+ if(config->tr_encoding)
+ my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1);
+
+ } /* (built_in_protos & CURLPROTO_HTTP) */
+
+ my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
+ my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
+ config->low_speed_limit);
+ my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
+ my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
+ config->sendpersecond);
+ my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
+ config->recvpersecond);
+ my_setopt(curl, CURLOPT_RESUME_FROM_LARGE,
+ config->use_resume?config->resume_from:0);
+
+ my_setopt(curl, CURLOPT_SSLCERT, config->cert);
+ my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
+ my_setopt(curl, CURLOPT_SSLKEY, config->key);
+ my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
+ my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
+
+ if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
+
+ /* SSH and SSL private key uses same command-line option */
+ /* new in libcurl 7.16.1 */
+ my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
+ /* new in libcurl 7.16.1 */
+ my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
+
+ /* new in libcurl 7.17.1: SSH host key md5 checking allows us
+ to fail if we are not talking to who we think we should */
+ my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
+ config->hostpubmd5);
+ }
+
+ if(config->cacert)
+ my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
+ if(config->capath)
+ my_setopt_str(curl, CURLOPT_CAPATH, config->capath);
+ if(config->crlfile)
+ my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
+
+ if(curlinfo->features & CURL_VERSION_SSL) {
+ if(config->insecure_ok) {
+ my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
+ my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
+ }
+ else {
+ my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
+ /* libcurl default is strict verifyhost -> 2L */
+ /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
+ }
+ }
+
+ if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
+ if(!config->insecure_ok) {
+ char *home;
+ char *file;
+ res = CURLE_OUT_OF_MEMORY;
+ home = homedir();
+ if(home) {
+ file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
+ if(file) {
+ /* new in curl 7.19.6 */
+ res = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
+ curl_free(file);
+ if(res == CURLE_UNKNOWN_OPTION)
+ /* libssh2 version older than 1.1.1 */
+ res = CURLE_OK;
+ }
+ Curl_safefree(home);
+ }
+ if(res)
+ goto show_error;
+ }
+ }
+
+ if(config->no_body || config->remote_time) {
+ /* no body or use remote time */
+ my_setopt(curl, CURLOPT_FILETIME, TRUE);
+ }
+
+ my_setopt(curl, CURLOPT_CRLF, config->crlf);
+ my_setopt_slist(curl, CURLOPT_QUOTE, config->quote);
+ my_setopt_slist(curl, CURLOPT_POSTQUOTE, config->postquote);
+ my_setopt_slist(curl, CURLOPT_PREQUOTE, config->prequote);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ {
+ /* TODO: Make this a run-time check instead of compile-time one. */
+
+ if(config->cookie)
+ my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
+
+ if(config->cookiefile)
+ my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
+
+ /* new in libcurl 7.9 */
+ if(config->cookiejar)
+ my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
+
+ /* new in libcurl 7.9.7 */
+ my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
+ }
+#endif
+
+ my_setopt_enum(curl, CURLOPT_SSLVERSION, config->ssl_version);
+ my_setopt_enum(curl, CURLOPT_TIMECONDITION, config->timecond);
+ my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
+ my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
+ my_setopt(curl, CURLOPT_STDERR, config->errors);
+
+ /* three new ones in libcurl 7.3: */
+ my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
+ my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
+
+ progressbarinit(&progressbar, config);
+ if((config->progressmode == CURL_PROGRESS_BAR) &&
+ !config->noprogress && !config->mute) {
+ /* we want the alternative style, then we have to implement it
+ ourselves! */
+ my_setopt(curl, CURLOPT_PROGRESSFUNCTION, tool_progress_cb);
+ my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
+ }
+
+ /* new in libcurl 7.6.2: */
+ my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
+
+ /* new in libcurl 7.7: */
+ my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
+ my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
+ my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
+
+ if(config->cipher_list)
+ my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
+
+ /* new in libcurl 7.9.2: */
+ if(config->disable_epsv)
+ /* disable it */
+ my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
+
+ /* new in libcurl 7.10.5 */
+ if(config->disable_eprt)
+ /* disable it */
+ my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
+
+ if(config->tracetype != TRACE_NONE) {
+ my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
+ my_setopt(curl, CURLOPT_DEBUGDATA, config);
+ my_setopt(curl, CURLOPT_VERBOSE, TRUE);
+ }
+
+ /* new in curl 7.9.3 */
+ if(config->engine) {
+ res = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
+ if(res)
+ goto show_error;
+ my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
+ }
+
+ /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */
+ my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
+ config->ftp_create_dirs);
+
+ /* new in curl 7.10.8 */
+ if(config->max_filesize)
+ my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
+ config->max_filesize);
+
+ if(4 == config->ip_version)
+ my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ else if(6 == config->ip_version)
+ my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
+ else
+ my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
+
+ /* new in curl 7.15.5 */
+ if(config->ftp_ssl_reqd)
+ my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
+
+ /* new in curl 7.11.0 */
+ else if(config->ftp_ssl)
+ my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
+
+ /* new in curl 7.16.0 */
+ else if(config->ftp_ssl_control)
+ my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
+
+ /* new in curl 7.16.1 */
+ if(config->ftp_ssl_ccc)
+ my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ {
+ /* TODO: Make this a run-time check instead of compile-time one. */
+
+ /* new in curl 7.19.4 */
+ if(config->socks5_gssapi_service)
+ my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE,
+ config->socks5_gssapi_service);
+
+ /* new in curl 7.19.4 */
+ if(config->socks5_gssapi_nec)
+ my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
+ config->socks5_gssapi_nec);
+ }
+#endif
+ /* curl 7.13.0 */
+ my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
+
+ my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
+
+ /* curl 7.14.2 */
+ my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
+
+ /* curl 7.15.1 */
+ my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
+
+ /* curl 7.15.2 */
+ if(config->localport) {
+ my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
+ my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
+ config->localportrange);
+ }
+
+ /* curl 7.15.5 */
+ my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
+ config->ftp_alternative_to_user);
+
+ /* curl 7.16.0 */
+ if(config->disable_sessionid)
+ my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE,
+ !config->disable_sessionid);
+
+ /* curl 7.16.2 */
+ if(config->raw) {
+ my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE);
+ my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE);
+ }
+
+ /* curl 7.17.1 */
+ if(!config->nokeepalive) {
+ my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
+ if(config->alivetime != 0) {
+#if !defined(TCP_KEEPIDLE) || !defined(TCP_KEEPINTVL)
+ warnf(config, "Keep-alive functionality somewhat crippled due to "
+ "missing support in your operating system!\n");
+#endif
+ my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
+ my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
+ }
+ }
+ else
+ my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
+
+ /* curl 7.20.0 */
+ if(config->tftp_blksize)
+ my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
+
+ if(config->mail_from)
+ my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
+
+ if(config->mail_rcpt)
+ my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
+
+ /* curl 7.20.x */
+ if(config->ftp_pret)
+ my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
+
+ if(config->proto_present)
+ my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto);
+ if(config->proto_redir_present)
+ my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
+
+ if(config->content_disposition
+ && (urlnode->flags & GETOUT_USEREMOTE)
+ && (checkprefix("http://", this_url) ||
+ checkprefix("https://", this_url)))
+ hdrcbdata.honor_cd_filename = TRUE;
+ else
+ hdrcbdata.honor_cd_filename = FALSE;
+
+ hdrcbdata.outs = &outs;
+ hdrcbdata.heads = &heads;
+
+ my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb);
+ my_setopt(curl, CURLOPT_HEADERDATA, &hdrcbdata);
+
+ if(config->resolve)
+ /* new in 7.21.3 */
+ my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve);
+
+ /* new in 7.21.4 */
+ if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
+ if(config->tls_username)
+ my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME,
+ config->tls_username);
+ if(config->tls_password)
+ my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD,
+ config->tls_password);
+ if(config->tls_authtype)
+ my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE,
+ config->tls_authtype);
+ }
+
+ /* new in 7.22.0 */
+ if(config->gssapi_delegation)
+ my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION,
+ config->gssapi_delegation);
+
+ /* new in 7.25.0 */
+ if(config->ssl_allow_beast)
+ my_setopt(curl, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_ALLOW_BEAST);
+
+ if(config->mail_auth)
+ my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth);
+
+ /* initialize retry vars for loop below */
+ retry_sleep_default = (config->retry_delay) ?
+ config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
+
+ retry_numretries = config->req_retry;
+ retry_sleep = retry_sleep_default; /* ms */
+ retrystart = tvnow();
+
+#ifndef CURL_DISABLE_LIBCURL_OPTION
+ res = easysrc_perform();
+ if(res) {
+ goto show_error;
+ }
+#endif
+
+ for(;;) {
+#ifdef USE_METALINK
+ if(!metalink && config->use_metalink) {
+ /* If outs.metalink_parser is non-NULL, delete it first. */
+ if(outs.metalink_parser)
+ metalink_parser_context_delete(outs.metalink_parser);
+ outs.metalink_parser = metalink_parser_context_new();
+ if(outs.metalink_parser == NULL) {
+ res = CURLE_OUT_OF_MEMORY;
+ goto show_error;
+ }
+ fprintf(config->errors, "Metalink: parsing (%s) metalink/XML...\n",
+ this_url);
+ }
+ else if(metalink)
+ fprintf(config->errors, "Metalink: fetching (%s) from (%s)...\n",
+ mlfile->filename, this_url);
+#endif /* USE_METALINK */
+
+ res = curl_easy_perform(curl);
+
+ if(outs.is_cd_filename && outs.stream && !config->mute &&
+ outs.filename)
+ printf("curl: Saved to filename '%s'\n", outs.filename);
+
+ /* if retry-max-time is non-zero, make sure we haven't exceeded the
+ time */
+ if(retry_numretries &&
+ (!config->retry_maxtime ||
+ (tvdiff(tvnow(), retrystart) <
+ config->retry_maxtime*1000L)) ) {
+ enum {
+ RETRY_NO,
+ RETRY_TIMEOUT,
+ RETRY_HTTP,
+ RETRY_FTP,
+ RETRY_LAST /* not used */
+ } retry = RETRY_NO;
+ long response;
+ if((CURLE_OPERATION_TIMEDOUT == res) ||
+ (CURLE_COULDNT_RESOLVE_HOST == res) ||
+ (CURLE_COULDNT_RESOLVE_PROXY == res) ||
+ (CURLE_FTP_ACCEPT_TIMEOUT == res))
+ /* retry timeout always */
+ retry = RETRY_TIMEOUT;
+ else if((CURLE_OK == res) ||
+ (config->failonerror &&
+ (CURLE_HTTP_RETURNED_ERROR == res))) {
+ /* If it returned OK. _or_ failonerror was enabled and it
+ returned due to such an error, check for HTTP transient
+ errors to retry on. */
+ char *effective_url = NULL;
+ curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
+ if(effective_url &&
+ checkprefix("http", effective_url)) {
+ /* This was HTTP(S) */
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
+
+ switch(response) {
+ case 500: /* Internal Server Error */
+ case 502: /* Bad Gateway */
+ case 503: /* Service Unavailable */
+ case 504: /* Gateway Timeout */
+ retry = RETRY_HTTP;
+ /*
+ * At this point, we have already written data to the output
+ * file (or terminal). If we write to a file, we must rewind
+ * or close/re-open the file so that the next attempt starts
+ * over from the beginning.
+ *
+ * TODO: similar action for the upload case. We might need
+ * to start over reading from a previous point if we have
+ * uploaded something when this was returned.
+ */
+ break;
+ }
+ }
+ } /* if CURLE_OK */
+ else if(res) {
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
+
+ if(response/100 == 4)
+ /*
+ * This is typically when the FTP server only allows a certain
+ * amount of users and we are not one of them. All 4xx codes
+ * are transient.
+ */
+ retry = RETRY_FTP;
+ }
+
+ if(retry) {
+ static const char * const m[]={
+ NULL, "timeout", "HTTP error", "FTP error"
+ };
+ warnf(config, "Transient problem: %s "
+ "Will retry in %ld seconds. "
+ "%ld retries left.\n",
+ m[retry], retry_sleep/1000L, retry_numretries);
+
+ tool_go_sleep(retry_sleep);
+ retry_numretries--;
+ if(!config->retry_delay) {
+ retry_sleep *= 2;
+ if(retry_sleep > RETRY_SLEEP_MAX)
+ retry_sleep = RETRY_SLEEP_MAX;
+ }
+ if(outs.bytes && outs.filename) {
+ /* We have written data to a output file, we truncate file
+ */
+ if(!config->mute)
+ fprintf(config->errors, "Throwing away %"
+ CURL_FORMAT_CURL_OFF_T " bytes\n",
+ outs.bytes);
+ fflush(outs.stream);
+ /* truncate file at the position where we started appending */
+#ifdef HAVE_FTRUNCATE
+ if(ftruncate( fileno(outs.stream), outs.init)) {
+ /* when truncate fails, we can't just append as then we'll
+ create something strange, bail out */
+ if(!config->mute)
+ fprintf(config->errors,
+ "failed to truncate, exiting\n");
+ res = CURLE_WRITE_ERROR;
+ goto quit_urls;
+ }
+ /* now seek to the end of the file, the position where we
+ just truncated the file in a large file-safe way */
+ fseek(outs.stream, 0, SEEK_END);
+#else
+ /* ftruncate is not available, so just reposition the file
+ to the location we would have truncated it. This won't
+ work properly with large files on 32-bit systems, but
+ most of those will have ftruncate. */
+ fseek(outs.stream, (long)outs.init, SEEK_SET);
+#endif
+ outs.bytes = 0; /* clear for next round */
+ }
+ continue; /* curl_easy_perform loop */
+ }
+ } /* if retry_numretries */
+ else if(metalink) {
+ /* Metalink: Decide to try the next resource or
+ not. Basically, we want to try the next resource if
+ download was not successful. */
+ long response;
+ if(CURLE_OK == res) {
+ /* TODO We want to try next resource when download was
+ not successful. How to know that? */
+ char *effective_url = NULL;
+ curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
+ if(effective_url &&
+ curlx_strnequal(effective_url, "http", 4)) {
+ /* This was HTTP(S) */
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
+ if(response != 200 && response != 206) {
+ metalink_next_res = 1;
+ fprintf(config->errors,
+ "Metalink: fetching (%s) from (%s) FAILED "
+ "(HTTP status code %d)\n",
+ mlfile->filename, this_url, response);
+ }
+ }
+ }
+ else {
+ metalink_next_res = 1;
+ fprintf(config->errors,
+ "Metalink: fetching (%s) from (%s) FAILED (%s)\n",
+ mlfile->filename, this_url,
+ (errorbuffer[0]) ?
+ errorbuffer : curl_easy_strerror((CURLcode)res));
+ }
+ }
+ if(metalink && !metalink_next_res)
+ fprintf(config->errors, "Metalink: fetching (%s) from (%s) OK\n",
+ mlfile->filename, this_url);
+
+ /* In all ordinary cases, just break out of loop here */
+ break; /* curl_easy_perform loop */
+
+ }
+
+ if((config->progressmode == CURL_PROGRESS_BAR) &&
+ progressbar.calls)
+ /* if the custom progress bar has been displayed, we output a
+ newline here */
+ fputs("\n", progressbar.out);
+
+ if(config->writeout)
+ ourWriteOut(curl, &outs, config->writeout);
+
+ if(config->writeenv)
+ ourWriteEnv(curl);
+
+ /*
+ ** Code within this loop may jump directly here to label 'show_error'
+ ** in order to display an error message for CURLcode stored in 'res'
+ ** variable and exit loop once that necessary writing and cleanup
+ ** in label 'quit_urls' has been done.
+ */
+
+ show_error:
+
+#ifdef __VMS
+ if(is_vms_shell()) {
+ /* VMS DCL shell behavior */
+ if(!config->showerror)
+ vms_show = VMSSTS_HIDE;
+ }
+ else
+#endif
+ if(res && config->showerror) {
+ fprintf(config->errors, "curl: (%d) %s\n", res, (errorbuffer[0]) ?
+ errorbuffer : curl_easy_strerror((CURLcode)res));
+ if(res == CURLE_SSL_CACERT)
+ fprintf(config->errors, "%s%s",
+ CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2);
+ }
+
+ /* Fall through comment to 'quit_urls' label */
+
+ /*
+ ** Upon error condition and always that a message has already been
+ ** displayed, code within this loop may jump directly here to label
+ ** 'quit_urls' otherwise it should jump to 'show_error' label above.
+ **
+ ** When 'res' variable is _not_ CURLE_OK loop will exit once that
+ ** all code following 'quit_urls' has been executed. Otherwise it
+ ** will loop to the beginning from where it may exit if there are
+ ** no more urls left.
+ */
+
+ quit_urls:
+
+ /* Set file extended attributes */
+ if(!res && config->xattr && outs.fopened && outs.stream) {
+ int rc = fwrite_xattr(curl, fileno(outs.stream));
+ if(rc)
+ warnf(config, "Error setting extended attributes: %s\n",
+ strerror(errno));
+ }
+
+ /* Close the file */
+ if(outs.fopened && outs.stream) {
+ int rc = fclose(outs.stream);
+ if(!res && rc) {
+ /* something went wrong in the writing process */
+ res = CURLE_WRITE_ERROR;
+ fprintf(config->errors, "(%d) Failed writing body\n", res);
+ }
+ }
+ else if(!outs.s_isreg && outs.stream) {
+ /* Dump standard stream buffered data */
+ int rc = fflush(outs.stream);
+ if(!res && rc) {
+ /* something went wrong in the writing process */
+ res = CURLE_WRITE_ERROR;
+ fprintf(config->errors, "(%d) Failed writing body\n", res);
+ }
+ }
+
+#ifdef __AMIGA__
+ if(!res && outs.s_isreg && outs.filename) {
+ /* Set the url (up to 80 chars) as comment for the file */
+ if(strlen(url) > 78)
+ url[79] = '\0';
+ SetComment(outs.filename, url);
+ }
+#endif
+
+#ifdef HAVE_UTIME
+ /* File time can only be set _after_ the file has been closed */
+ if(!res && config->remote_time && outs.s_isreg && outs.filename) {
+ /* Ask libcurl if we got a remote file time */
+ long filetime = -1;
+ curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
+ if(filetime >= 0) {
+ struct utimbuf times;
+ times.actime = (time_t)filetime;
+ times.modtime = (time_t)filetime;
+ utime(outs.filename, &times); /* set the time we got */
+ }
+ }
+#endif
+
+#ifdef USE_METALINK
+ if(!metalink && config->use_metalink && res == CURLE_OK) {
+ int rv = parse_metalink(config, &outs, this_url);
+ if(rv == 0)
+ fprintf(config->errors, "Metalink: parsing (%s) OK\n", this_url);
+ else if(rv == -1)
+ fprintf(config->errors, "Metalink: parsing (%s) FAILED\n",
+ this_url);
+ }
+ else if(metalink && res == CURLE_OK && !metalink_next_res) {
+ int rv = metalink_check_hash(config, mlfile, outs.filename);
+ if(rv == 0) {
+ metalink_next_res = 1;
+ }
+ }
+#endif /* USE_METALINK */
+
+ /* No more business with this output struct */
+ if(outs.alloc_filename)
+ Curl_safefree(outs.filename);
+#ifdef USE_METALINK
+ if(outs.metalink_parser)
+ metalink_parser_context_delete(outs.metalink_parser);
+#endif /* USE_METALINK */
+ memset(&outs, 0, sizeof(struct OutStruct));
+ hdrcbdata.outs = NULL;
+
+ /* Free loop-local allocated memory and close loop-local opened fd */
+
+ Curl_safefree(outfile);
+ Curl_safefree(this_url);
+
+ if(infdopen)
+ close(infd);
+
+ if(metalink) {
+ /* Should exit if error is fatal. */
+ if(is_fatal_error(res)) {
+ break;
+ }
+ if(!metalink_next_res)
+ break;
+ mlres = mlres->next;
+ if(mlres == NULL)
+ /* TODO If metalink_next_res is 1 and mlres is NULL,
+ * set res to error code
+ */
+ break;
+ }
+ else
+ if(urlnum > 1) {
+ /* when url globbing, exit loop upon critical error */
+ if(is_fatal_error(res))
+ break;
+ }
+ else if(res)
+ /* when not url globbing, exit loop upon any error */
+ break;
+
+ } /* loop to the next URL */
+
+ /* Free loop-local allocated memory */
+
+ Curl_safefree(uploadfile);
+
+ if(urls) {
+ /* Free list of remaining URLs */
+ glob_cleanup(urls);
+ urls = NULL;
+ }
+
+ if(infilenum > 1) {
+ /* when file globbing, exit loop upon critical error */
+ if(is_fatal_error(res))
+ break;
+ }
+ else if(res)
+ /* when not file globbing, exit loop upon any error */
+ break;
+
+ } /* loop to the next globbed upload file */
+
+ /* Free loop-local allocated memory */
+
+ Curl_safefree(outfiles);
+
+ if(inglob) {
+ /* Free list of globbed upload files */
+ glob_cleanup(inglob);
+ inglob = NULL;
+ }
+
+ /* Free this URL node data without destroying the
+ the node itself nor modifying next pointer. */
+ Curl_safefree(urlnode->url);
+ Curl_safefree(urlnode->outfile);
+ Curl_safefree(urlnode->infile);
+ urlnode->flags = 0;
+
+ /*
+ ** Bail out upon critical errors
+ */
+ if(is_fatal_error(res))
+ goto quit_curl;
+
+ } /* for-loop through all URLs */
+
+ /*
+ ** Nested loops end here.
+ */
+
+ quit_curl:
+
+ /* Free function-local referenced allocated memory */
+ Curl_safefree(httpgetfields);
+
+ /* Free list of given URLs */
+ clean_getout(config);
+
+ /* Cleanup the curl handle now that our
+ progressbar struct is still in scope */
+ if(curl) {
+ curl_easy_cleanup(curl);
+ config->easy = curl = NULL;
+ }
+#ifndef CURL_DISABLE_LIBCURL_OPTION
+ easysrc_cleanup();
+#endif
+
+ hdrcbdata.heads = NULL;
+
+ /* Close function-local opened file descriptors */
+
+ if(heads.fopened && heads.stream)
+ fclose(heads.stream);
+ if(heads.alloc_filename)
+ Curl_safefree(heads.filename);
+
+ if(config->trace_fopened && config->trace_stream)
+ fclose(config->trace_stream);
+
+#ifndef CURL_DISABLE_LIBCURL_OPTION
+ /* Dump the libcurl code if previously enabled.
+ NOTE: that this function relies on config->errors amongst other things
+ so not everything can be closed and cleaned before this is called */
+ dumpeasysrc(config);
+#endif
+
+ if(config->errors_fopened && config->errors)
+ fclose(config->errors);
+
+ /* Release metalink related resources here */
+ clean_metalink(config);
+
+ main_free(); /* cleanup */
+
+ return res;
+}
+
diff --git a/src/tool_operate.h b/src/tool_operate.h
new file mode 100644
index 000000000..5a0a4a06b
--- /dev/null
+++ b/src/tool_operate.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TOOL_OPERATE_H
+#define HEADER_CURL_TOOL_OPERATE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+int operate(struct Configurable *config, int argc, argv_item_t argv[]);
+
+#endif /* HEADER_CURL_TOOL_OPERATE_H */
+
diff --git a/src/tool_operhlp.c b/src/tool_operhlp.c
new file mode 100644
index 000000000..9078b9564
--- /dev/null
+++ b/src/tool_operhlp.c
@@ -0,0 +1,257 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_convert.h"
+#include "tool_operhlp.h"
+#include "tool_version.h"
+
+#ifdef USE_METALINK
+/* import the declaration of metalink_cleanup() */
+# include "tool_metalink.h"
+#endif
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/*
+ * my_useragent: returns allocated string with default user agent
+ */
+char *my_useragent(void)
+{
+ return strdup( CURL_NAME "/" CURL_VERSION );
+}
+
+/*
+ * Print list of OpenSSL supported engines
+ */
+void list_engines(const struct curl_slist *engines)
+{
+ puts("Build-time engines:");
+ if(!engines) {
+ puts(" <none>");
+ return;
+ }
+ for(; engines; engines = engines->next)
+ printf(" %s\n", engines->data);
+}
+
+void clean_getout(struct Configurable *config)
+{
+ struct getout *next;
+ struct getout *node = config->url_list;
+
+ while(node) {
+ next = node->next;
+ Curl_safefree(node->url);
+ Curl_safefree(node->outfile);
+ Curl_safefree(node->infile);
+ Curl_safefree(node);
+ node = next;
+ }
+ config->url_list = NULL;
+}
+
+bool output_expected(const char *url, const char *uploadfile)
+{
+ if(!uploadfile)
+ return TRUE; /* download */
+ if(checkprefix("http://", url) || checkprefix("https://", url))
+ return TRUE; /* HTTP(S) upload */
+
+ return FALSE; /* non-HTTP upload, probably no output should be expected */
+}
+
+bool stdin_upload(const char *uploadfile)
+{
+ return (curlx_strequal(uploadfile, "-") ||
+ curlx_strequal(uploadfile, ".")) ? TRUE : FALSE;
+}
+
+/*
+ * Adds the file name to the URL if it doesn't already have one.
+ * url will be freed before return if the returned pointer is different
+ */
+char *add_file_name_to_url(CURL *curl, char *url, const char *filename)
+{
+ /* If no file name part is given in the URL, we add this file name */
+ char *ptr = strstr(url, "://");
+ if(ptr)
+ ptr += 3;
+ else
+ ptr = url;
+ ptr = strrchr(ptr, '/');
+ if(!ptr || !strlen(++ptr)) {
+ /* The URL has no file name part, add the local file name. In order
+ to be able to do so, we have to create a new URL in another
+ buffer.*/
+
+ /* We only want the part of the local path that is on the right
+ side of the rightmost slash and backslash. */
+ const char *filep = strrchr(filename, '/');
+ char *file2 = strrchr(filep?filep:filename, '\\');
+ char *encfile;
+
+ if(file2)
+ filep = file2 + 1;
+ else if(filep)
+ filep++;
+ else
+ filep = filename;
+
+ /* URL encode the file name */
+ encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
+ if(encfile) {
+ char *urlbuffer = malloc(strlen(url) + strlen(encfile) + 3);
+ if(!urlbuffer) {
+ curl_free(encfile);
+ Curl_safefree(url);
+ return NULL;
+ }
+ if(ptr)
+ /* there is a trailing slash on the URL */
+ sprintf(urlbuffer, "%s%s", url, encfile);
+ else
+ /* there is no trailing slash on the URL */
+ sprintf(urlbuffer, "%s/%s", url, encfile);
+
+ curl_free(encfile);
+ Curl_safefree(url);
+
+ url = urlbuffer; /* use our new URL instead! */
+ }
+ }
+ return url;
+}
+
+/* Extracts the name portion of the URL.
+ * Returns a pointer to a heap-allocated string or NULL if
+ * no name part, at location indicated by first argument.
+ */
+CURLcode get_url_file_name(char **filename, const char *url)
+{
+ const char *pc;
+
+ *filename = NULL;
+
+ /* Find and get the remote file name */
+ pc = strstr(url, "://");
+ if(pc)
+ pc += 3;
+ else
+ pc = url;
+ pc = strrchr(pc, '/');
+
+ if(pc) {
+ /* duplicate the string beyond the slash */
+ pc++;
+ if(*pc) {
+ *filename = strdup(pc);
+ if(!*filename)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* in case we built debug enabled, we allow an environment variable
+ * named CURL_TESTDIR to prefix the given file name to put it into a
+ * specific directory
+ */
+#ifdef DEBUGBUILD
+ {
+ char *tdir = curlx_getenv("CURL_TESTDIR");
+ if(tdir) {
+ char buffer[512]; /* suitably large */
+ snprintf(buffer, sizeof(buffer), "%s/%s", tdir, *filename);
+ Curl_safefree(*filename);
+ *filename = strdup(buffer); /* clone the buffer */
+ curl_free(tdir);
+ }
+ }
+#endif
+
+ return CURLE_OK;
+}
+
+/*
+ * This is the main global constructor for the app. Call this before
+ * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
+ * used, or havoc may be the result.
+ */
+CURLcode main_init(void)
+{
+#if defined(__DJGPP__) || defined(__GO32__)
+ /* stop stat() wasting time */
+ _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
+#endif
+
+ return curl_global_init(CURL_GLOBAL_DEFAULT);
+}
+
+/*
+ * This is the main global destructor for the app. Call this after
+ * _all_ libcurl usage is done.
+ */
+void main_free(void)
+{
+ curl_global_cleanup();
+ convert_cleanup();
+#ifdef USE_METALINK
+ metalink_cleanup();
+#endif
+}
+
+#ifdef CURLDEBUG
+void memory_tracking_init(void)
+{
+ char *env;
+ /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
+ env = curlx_getenv("CURL_MEMDEBUG");
+ if(env) {
+ /* use the value as file name */
+ char fname[CURL_MT_LOGFNAME_BUFSIZE];
+ if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE)
+ env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0';
+ strcpy(fname, env);
+ curl_free(env);
+ curl_memdebug(fname);
+ /* this weird stuff here is to make curl_free() get called
+ before curl_memdebug() as otherwise memory tracking will
+ log a free() without an alloc! */
+ }
+ /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */
+ env = curlx_getenv("CURL_MEMLIMIT");
+ if(env) {
+ char *endptr;
+ long num = strtol(env, &endptr, 10);
+ if((endptr != env) && (endptr == env + strlen(env)) && (num > 0))
+ curl_memlimit(num);
+ curl_free(env);
+ }
+}
+#endif
+
diff --git a/src/tool_operhlp.h b/src/tool_operhlp.h
new file mode 100644
index 000000000..806717ee0
--- /dev/null
+++ b/src/tool_operhlp.h
@@ -0,0 +1,51 @@
+#ifndef HEADER_CURL_TOOL_OPERHLP_H
+#define HEADER_CURL_TOOL_OPERHLP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+char *my_useragent(void);
+
+void list_engines(const struct curl_slist *engines);
+
+void clean_getout(struct Configurable *config);
+
+bool output_expected(const char *url, const char *uploadfile);
+
+bool stdin_upload(const char *uploadfile);
+
+char *add_file_name_to_url(CURL *curl, char *url, const char *filename);
+
+CURLcode get_url_file_name(char **filename, const char *url);
+
+CURLcode main_init(void);
+
+void main_free(void);
+
+#ifdef CURLDEBUG
+void memory_tracking_init(void);
+#else
+# define memory_tracking_init() Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_TOOL_OPERHLP_H */
+
diff --git a/src/tool_panykey.c b/src/tool_panykey.c
new file mode 100644
index 000000000..d8718e328
--- /dev/null
+++ b/src/tool_panykey.c
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#if defined(__SYMBIAN32__) || defined(NETWARE)
+
+#ifdef NETWARE
+# ifdef __NOVELL_LIBC__
+# include <screen.h>
+# else
+# include <nwconio.h>
+# endif
+#endif
+
+#include "tool_panykey.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+void tool_pressanykey(void)
+{
+#if defined(__SYMBIAN32__)
+ getchar();
+#elif defined(NETWARE)
+ pressanykey();
+#endif
+}
+
+#endif /* __SYMBIAN32__ || NETWARE */
+
diff --git a/src/tool_panykey.h b/src/tool_panykey.h
new file mode 100644
index 000000000..50b15d2db
--- /dev/null
+++ b/src/tool_panykey.h
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_TOOL_PANYKEY_H
+#define HEADER_CURL_TOOL_PANYKEY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#if defined(__SYMBIAN32__) || defined(NETWARE)
+
+void tool_pressanykey(void);
+
+#else
+
+#define tool_pressanykey() Curl_nop_stmt
+
+#endif
+
+#endif /* HEADER_CURL_TOOL_PANYKEY_H */
+
diff --git a/src/tool_paramhlp.c b/src/tool_paramhlp.c
new file mode 100644
index 000000000..5d6f8bbc5
--- /dev/null
+++ b/src/tool_paramhlp.c
@@ -0,0 +1,407 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "rawstr.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_getparam.h"
+#include "tool_getpass.h"
+#include "tool_homedir.h"
+#include "tool_msgs.h"
+#include "tool_paramhlp.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+struct getout *new_getout(struct Configurable *config)
+{
+ struct getout *node = calloc(1, sizeof(struct getout));
+ struct getout *last = config->url_last;
+ if(node) {
+ /* append this new node last in the list */
+ if(last)
+ last->next = node;
+ else
+ config->url_list = node; /* first node */
+
+ /* move the last pointer */
+ config->url_last = node;
+
+ node->flags = config->default_node_flags;
+ }
+ return node;
+}
+
+ParameterError file2string(char **bufp, FILE *file)
+{
+ char buffer[256];
+ char *ptr;
+ char *string = NULL;
+ size_t stringlen = 0;
+ size_t buflen;
+
+ if(file) {
+ while(fgets(buffer, sizeof(buffer), file)) {
+ if((ptr = strchr(buffer, '\r')) != NULL)
+ *ptr = '\0';
+ if((ptr = strchr(buffer, '\n')) != NULL)
+ *ptr = '\0';
+ buflen = strlen(buffer);
+ if((ptr = realloc(string, stringlen+buflen+1)) == NULL) {
+ Curl_safefree(string);
+ return PARAM_NO_MEM;
+ }
+ string = ptr;
+ strcpy(string+stringlen, buffer);
+ stringlen += buflen;
+ }
+ }
+ *bufp = string;
+ return PARAM_OK;
+}
+
+ParameterError file2memory(char **bufp, size_t *size, FILE *file)
+{
+ char *newbuf;
+ char *buffer = NULL;
+ size_t alloc = 512;
+ size_t nused = 0;
+ size_t nread;
+
+ if(file) {
+ do {
+ if(!buffer || (alloc == nused)) {
+ /* size_t overflow detection for huge files */
+ if(alloc+1 > ((size_t)-1)/2) {
+ Curl_safefree(buffer);
+ return PARAM_NO_MEM;
+ }
+ alloc *= 2;
+ /* allocate an extra char, reserved space, for null termination */
+ if((newbuf = realloc(buffer, alloc+1)) == NULL) {
+ Curl_safefree(buffer);
+ return PARAM_NO_MEM;
+ }
+ buffer = newbuf;
+ }
+ nread = fread(buffer+nused, 1, alloc-nused, file);
+ nused += nread;
+ } while(nread);
+ /* null terminate the buffer in case it's used as a string later */
+ buffer[nused] = '\0';
+ /* free trailing slack space, if possible */
+ if(alloc != nused) {
+ if((newbuf = realloc(buffer, nused+1)) == NULL) {
+ Curl_safefree(buffer);
+ return PARAM_NO_MEM;
+ }
+ buffer = newbuf;
+ }
+ /* discard buffer if nothing was read */
+ if(!nused) {
+ Curl_safefree(buffer); /* no string */
+ }
+ }
+ *size = nused;
+ *bufp = buffer;
+ return PARAM_OK;
+}
+
+void cleanarg(char *str)
+{
+#ifdef HAVE_WRITABLE_ARGV
+ /* now that GetStr has copied the contents of nextarg, wipe the next
+ * argument out so that the username:password isn't displayed in the
+ * system process list */
+ if(str) {
+ size_t len = strlen(str);
+ memset(str, ' ', len);
+ }
+#else
+ (void)str;
+#endif
+}
+
+/*
+ * Parse the string and write the long in the given address. Return PARAM_OK
+ * on success, otherwise a parameter specific error enum.
+ *
+ * Since this function gets called with the 'nextarg' pointer from within the
+ * getparameter a lot, we must check it for NULL before accessing the str
+ * data.
+ */
+
+ParameterError str2num(long *val, const char *str)
+{
+ if(str) {
+ char *endptr;
+ long num = strtol(str, &endptr, 10);
+ if((endptr != str) && (endptr == str + strlen(str))) {
+ *val = num;
+ return PARAM_OK; /* Ok */
+ }
+ }
+ return PARAM_BAD_NUMERIC; /* badness */
+}
+
+/*
+ * Parse the string and write the long in the given address. Return PARAM_OK
+ * on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
+ *
+ * Since this function gets called with the 'nextarg' pointer from within the
+ * getparameter a lot, we must check it for NULL before accessing the str
+ * data.
+ */
+
+ParameterError str2unum(long *val, const char *str)
+{
+ if(str[0]=='-')
+ return PARAM_NEGATIVE_NUMERIC; /* badness */
+ return str2num(val, str);
+}
+
+/*
+ * Parse the string and modify the long in the given address. Return
+ * non-zero on failure, zero on success.
+ *
+ * The string is a list of protocols
+ *
+ * Since this function gets called with the 'nextarg' pointer from within the
+ * getparameter a lot, we must check it for NULL before accessing the str
+ * data.
+ */
+
+long proto2num(struct Configurable *config, long *val, const char *str)
+{
+ char *buffer;
+ const char *sep = ",";
+ char *token;
+
+ static struct sprotos {
+ const char *name;
+ long bit;
+ } const protos[] = {
+ { "all", CURLPROTO_ALL },
+ { "http", CURLPROTO_HTTP },
+ { "https", CURLPROTO_HTTPS },
+ { "ftp", CURLPROTO_FTP },
+ { "ftps", CURLPROTO_FTPS },
+ { "scp", CURLPROTO_SCP },
+ { "sftp", CURLPROTO_SFTP },
+ { "telnet", CURLPROTO_TELNET },
+ { "ldap", CURLPROTO_LDAP },
+ { "ldaps", CURLPROTO_LDAPS },
+ { "dict", CURLPROTO_DICT },
+ { "file", CURLPROTO_FILE },
+ { "tftp", CURLPROTO_TFTP },
+ { "imap", CURLPROTO_IMAP },
+ { "imaps", CURLPROTO_IMAPS },
+ { "pop3", CURLPROTO_POP3 },
+ { "pop3s", CURLPROTO_POP3S },
+ { "smtp", CURLPROTO_SMTP },
+ { "smtps", CURLPROTO_SMTPS },
+ { "rtsp", CURLPROTO_RTSP },
+ { "gopher", CURLPROTO_GOPHER },
+ { NULL, 0 }
+ };
+
+ if(!str)
+ return 1;
+
+ buffer = strdup(str); /* because strtok corrupts it */
+ if(!buffer)
+ return 1;
+
+ for(token = strtok(buffer, sep);
+ token;
+ token = strtok(NULL, sep)) {
+ enum e_action { allow, deny, set } action = allow;
+
+ struct sprotos const *pp;
+
+ /* Process token modifiers */
+ while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
+ switch (*token++) {
+ case '=':
+ action = set;
+ break;
+ case '-':
+ action = deny;
+ break;
+ case '+':
+ action = allow;
+ break;
+ default: /* Includes case of terminating NULL */
+ Curl_safefree(buffer);
+ return 1;
+ }
+ }
+
+ for(pp=protos; pp->name; pp++) {
+ if(curlx_raw_equal(token, pp->name)) {
+ switch (action) {
+ case deny:
+ *val &= ~(pp->bit);
+ break;
+ case allow:
+ *val |= pp->bit;
+ break;
+ case set:
+ *val = pp->bit;
+ break;
+ }
+ break;
+ }
+ }
+
+ if(!(pp->name)) { /* unknown protocol */
+ /* If they have specified only this protocol, we say treat it as
+ if no protocols are allowed */
+ if(action == set)
+ *val = 0;
+ warnf(config, "unrecognized protocol '%s'\n", token);
+ }
+ }
+ Curl_safefree(buffer);
+ return 0;
+}
+
+/**
+ * Parses the given string looking for an offset (which may be a
+ * larger-than-integer value). The offset CANNOT be negative!
+ *
+ * @param val the offset to populate
+ * @param str the buffer containing the offset
+ * @return PARAM_OK if successful, a parameter specific error enum if failure.
+ */
+ParameterError str2offset(curl_off_t *val, const char *str)
+{
+ char *endptr;
+ if(str[0] == '-')
+ /* offsets aren't negative, this indicates weird input */
+ return PARAM_NEGATIVE_NUMERIC;
+
+#if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+ *val = curlx_strtoofft(str, &endptr, 0);
+ if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (ERRNO == ERANGE))
+ return PARAM_BAD_NUMERIC;
+#else
+ *val = strtol(str, &endptr, 0);
+ if((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE)
+ return PARAM_BAD_NUMERIC;
+#endif
+ if((endptr != str) && (endptr == str + strlen(str)))
+ return PARAM_OK;
+
+ return PARAM_BAD_NUMERIC;
+}
+
+ParameterError checkpasswd(const char *kind, /* for what purpose */
+ char **userpwd) /* pointer to allocated string */
+{
+ char *ptr;
+
+ if(!*userpwd)
+ return PARAM_OK;
+
+ ptr = strchr(*userpwd, ':');
+ if(!ptr) {
+ /* no password present, prompt for one */
+ char passwd[256] = "";
+ char prompt[256];
+ size_t passwdlen;
+ size_t userlen = strlen(*userpwd);
+ char *passptr;
+
+ /* build a nice-looking prompt */
+ curlx_msnprintf(prompt, sizeof(prompt),
+ "Enter %s password for user '%s':",
+ kind, *userpwd);
+
+ /* get password */
+ getpass_r(prompt, passwd, sizeof(passwd));
+ passwdlen = strlen(passwd);
+
+ /* extend the allocated memory area to fit the password too */
+ passptr = realloc(*userpwd,
+ passwdlen + 1 + /* an extra for the colon */
+ userlen + 1); /* an extra for the zero */
+ if(!passptr)
+ return PARAM_NO_MEM;
+
+ /* append the password separated with a colon */
+ passptr[userlen] = ':';
+ memcpy(&passptr[userlen+1], passwd, passwdlen+1);
+ *userpwd = passptr;
+ }
+ return PARAM_OK;
+}
+
+ParameterError add2list(struct curl_slist **list, const char *ptr)
+{
+ struct curl_slist *newlist = curl_slist_append(*list, ptr);
+ if(newlist)
+ *list = newlist;
+ else
+ return PARAM_NO_MEM;
+
+ return PARAM_OK;
+}
+
+int ftpfilemethod(struct Configurable *config, const char *str)
+{
+ if(curlx_raw_equal("singlecwd", str))
+ return CURLFTPMETHOD_SINGLECWD;
+ if(curlx_raw_equal("nocwd", str))
+ return CURLFTPMETHOD_NOCWD;
+ if(curlx_raw_equal("multicwd", str))
+ return CURLFTPMETHOD_MULTICWD;
+ warnf(config, "unrecognized ftp file method '%s', using default\n", str);
+ return CURLFTPMETHOD_MULTICWD;
+}
+
+int ftpcccmethod(struct Configurable *config, const char *str)
+{
+ if(curlx_raw_equal("passive", str))
+ return CURLFTPSSL_CCC_PASSIVE;
+ if(curlx_raw_equal("active", str))
+ return CURLFTPSSL_CCC_ACTIVE;
+ warnf(config, "unrecognized ftp CCC method '%s', using default\n", str);
+ return CURLFTPSSL_CCC_PASSIVE;
+}
+
+long delegation(struct Configurable *config, char *str)
+{
+ if(curlx_raw_equal("none", str))
+ return CURLGSSAPI_DELEGATION_NONE;
+ if(curlx_raw_equal("policy", str))
+ return CURLGSSAPI_DELEGATION_POLICY_FLAG;
+ if(curlx_raw_equal("always", str))
+ return CURLGSSAPI_DELEGATION_FLAG;
+ warnf(config, "unrecognized delegation method '%s', using none\n", str);
+ return CURLGSSAPI_DELEGATION_NONE;
+}
+
diff --git a/src/tool_paramhlp.h b/src/tool_paramhlp.h
new file mode 100644
index 000000000..de1604e90
--- /dev/null
+++ b/src/tool_paramhlp.h
@@ -0,0 +1,52 @@
+#ifndef HEADER_CURL_TOOL_PARAMHLP_H
+#define HEADER_CURL_TOOL_PARAMHLP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+struct getout *new_getout(struct Configurable *config);
+
+ParameterError file2string(char **bufp, FILE *file);
+
+ParameterError file2memory(char **bufp, size_t *size, FILE *file);
+
+void cleanarg(char *str);
+
+ParameterError str2num(long *val, const char *str);
+ParameterError str2unum(long *val, const char *str);
+
+long proto2num(struct Configurable *config, long *val, const char *str);
+
+ParameterError str2offset(curl_off_t *val, const char *str);
+
+ParameterError checkpasswd(const char *kind, char **userpwd);
+
+ParameterError add2list(struct curl_slist **list, const char *ptr);
+
+int ftpfilemethod(struct Configurable *config, const char *str);
+
+int ftpcccmethod(struct Configurable *config, const char *str);
+
+long delegation(struct Configurable *config, char *str);
+
+#endif /* HEADER_CURL_TOOL_PARAMHLP_H */
+
diff --git a/src/tool_parsecfg.c b/src/tool_parsecfg.c
new file mode 100644
index 000000000..561dada11
--- /dev/null
+++ b/src/tool_parsecfg.c
@@ -0,0 +1,306 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_getparam.h"
+#include "tool_helpers.h"
+#include "tool_homedir.h"
+#include "tool_msgs.h"
+#include "tool_parsecfg.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#define CURLRC DOT_CHAR "curlrc"
+#define ISSEP(x) (((x) == '=') || ((x) == ':'))
+
+static const char *unslashquote(const char *line, char *param);
+static char *my_get_line(FILE *fp);
+
+/* return 0 on everything-is-fine, and non-zero otherwise */
+int parseconfig(const char *filename,
+ struct Configurable *config)
+{
+ int res;
+ FILE *file;
+ char filebuffer[512];
+ bool usedarg;
+ char *home;
+ int rc = 0;
+
+ if(!filename || !*filename) {
+ /* NULL or no file name attempts to load .curlrc from the homedir! */
+
+#ifndef __AMIGA__
+ filename = CURLRC; /* sensible default */
+ home = homedir(); /* portable homedir finder */
+ if(home) {
+ if(strlen(home) < (sizeof(filebuffer) - strlen(CURLRC))) {
+ snprintf(filebuffer, sizeof(filebuffer),
+ "%s%s%s", home, DIR_CHAR, CURLRC);
+
+#ifdef WIN32
+ /* Check if the file exists - if not, try CURLRC in the same
+ * directory as our executable
+ */
+ file = fopen(filebuffer, "r");
+ if(file != NULL) {
+ fclose(file);
+ filename = filebuffer;
+ }
+ else {
+ /* Get the filename of our executable. GetModuleFileName is
+ * already declared via inclusions done in setup header file.
+ * We assume that we are using the ASCII version here.
+ */
+ int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer));
+ if(n > 0 && n < (int)sizeof(filebuffer)) {
+ /* We got a valid filename - get the directory part */
+ char *lastdirchar = strrchr(filebuffer, '\\');
+ if(lastdirchar) {
+ size_t remaining;
+ *lastdirchar = 0;
+ /* If we have enough space, build the RC filename */
+ remaining = sizeof(filebuffer) - strlen(filebuffer);
+ if(strlen(CURLRC) < remaining - 1) {
+ snprintf(lastdirchar, remaining,
+ "%s%s", DIR_CHAR, CURLRC);
+ /* Don't bother checking if it exists - we do
+ * that later
+ */
+ filename = filebuffer;
+ }
+ }
+ }
+ }
+#else /* WIN32 */
+ filename = filebuffer;
+#endif /* WIN32 */
+ }
+ Curl_safefree(home); /* we've used it, now free it */
+ }
+
+# else /* __AMIGA__ */
+ /* On AmigaOS all the config files are into env:
+ */
+ filename = "ENV:" CURLRC;
+
+#endif
+ }
+
+ if(strcmp(filename,"-"))
+ file = fopen(filename, "r");
+ else
+ file = stdin;
+
+ if(file) {
+ char *line;
+ char *aline;
+ char *option;
+ char *param;
+ int lineno = 0;
+ bool alloced_param;
+
+ while(NULL != (aline = my_get_line(file))) {
+ lineno++;
+ line = aline;
+ alloced_param=FALSE;
+
+ /* line with # in the first non-blank column is a comment! */
+ while(*line && ISSPACE(*line))
+ line++;
+
+ switch(*line) {
+ case '#':
+ case '/':
+ case '\r':
+ case '\n':
+ case '*':
+ case '\0':
+ Curl_safefree(aline);
+ continue;
+ }
+
+ /* the option keywords starts here */
+ option = line;
+ while(*line && !ISSPACE(*line) && !ISSEP(*line))
+ line++;
+ /* ... and has ended here */
+
+ if(*line)
+ *line++ = '\0'; /* zero terminate, we have a local copy of the data */
+
+#ifdef DEBUG_CONFIG
+ fprintf(stderr, "GOT: %s\n", option);
+#endif
+
+ /* pass spaces and separator(s) */
+ while(*line && (ISSPACE(*line) || ISSEP(*line)))
+ line++;
+
+ /* the parameter starts here (unless quoted) */
+ if(*line == '\"') {
+ /* quoted parameter, do the quote dance */
+ line++;
+ param = malloc(strlen(line) + 1); /* parameter */
+ if(!param) {
+ /* out of memory */
+ Curl_safefree(aline);
+ rc = 1;
+ break;
+ }
+ alloced_param = TRUE;
+ (void)unslashquote(line, param);
+ }
+ else {
+ param = line; /* parameter starts here */
+ while(*line && !ISSPACE(*line))
+ line++;
+ *line = '\0'; /* zero terminate */
+ }
+
+ if(param && !*param) {
+ /* do this so getparameter can check for required parameters.
+ Otherwise it always thinks there's a parameter. */
+ if(alloced_param)
+ Curl_safefree(param);
+ param = NULL;
+ }
+
+#ifdef DEBUG_CONFIG
+ fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
+#endif
+ res = getparameter(option, param, &usedarg, config);
+
+ if(param && *param && !usedarg)
+ /* we passed in a parameter that wasn't used! */
+ res = PARAM_GOT_EXTRA_PARAMETER;
+
+ if(res != PARAM_OK) {
+ /* the help request isn't really an error */
+ if(!strcmp(filename, "-")) {
+ filename = (char *)"<stdin>";
+ }
+ if(PARAM_HELP_REQUESTED != res) {
+ const char *reason = param2text(res);
+ warnf(config, "%s:%d: warning: '%s' %s\n",
+ filename, lineno, option, reason);
+ }
+ }
+
+ if(alloced_param)
+ Curl_safefree(param);
+
+ Curl_safefree(aline);
+ }
+ if(file != stdin)
+ fclose(file);
+ }
+ else
+ rc = 1; /* couldn't open the file */
+
+ return rc;
+}
+
+/*
+ * Copies the string from line to the buffer at param, unquoting
+ * backslash-quoted characters and NUL-terminating the output string.
+ * Stops at the first non-backslash-quoted double quote character or the
+ * end of the input string. param must be at least as long as the input
+ * string. Returns the pointer after the last handled input character.
+ */
+static const char *unslashquote(const char *line, char *param)
+{
+ while(*line && (*line != '\"')) {
+ if(*line == '\\') {
+ char out;
+ line++;
+
+ /* default is to output the letter after the backslash */
+ switch(out = *line) {
+ case '\0':
+ continue; /* this'll break out of the loop */
+ case 't':
+ out = '\t';
+ break;
+ case 'n':
+ out = '\n';
+ break;
+ case 'r':
+ out = '\r';
+ break;
+ case 'v':
+ out = '\v';
+ break;
+ }
+ *param++ = out;
+ line++;
+ }
+ else
+ *param++ = *line++;
+ }
+ *param = '\0'; /* always zero terminate */
+ return line;
+}
+
+/*
+ * Reads a line from the given file, ensuring is NUL terminated.
+ * The pointer must be freed by the caller.
+ * NULL is returned on an out of memory condition.
+ */
+static char *my_get_line(FILE *fp)
+{
+ char buf[4096];
+ char *nl = NULL;
+ char *retval = NULL;
+
+ do {
+ if(NULL == fgets(buf, sizeof(buf), fp))
+ break;
+ if(!retval) {
+ retval = strdup(buf);
+ if(!retval)
+ return NULL;
+ }
+ else {
+ char *ptr;
+ ptr = realloc(retval, strlen(retval) + strlen(buf) + 1);
+ if(!ptr) {
+ Curl_safefree(retval);
+ return NULL;
+ }
+ retval = ptr;
+ strcat(retval, buf);
+ }
+ nl = strchr(retval, '\n');
+ } while(!nl);
+
+ if(nl)
+ *nl = '\0';
+
+ return retval;
+}
+
diff --git a/src/tool_parsecfg.h b/src/tool_parsecfg.h
new file mode 100644
index 000000000..aa7ac574b
--- /dev/null
+++ b/src/tool_parsecfg.h
@@ -0,0 +1,30 @@
+#ifndef HEADER_CURL_TOOL_PARSECFG_H
+#define HEADER_CURL_TOOL_PARSECFG_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+int parseconfig(const char *filename,
+ struct Configurable *config);
+
+#endif /* HEADER_CURL_TOOL_PARSECFG_H */
+
diff --git a/src/tool_sdecls.h b/src/tool_sdecls.h
new file mode 100644
index 000000000..5468830d0
--- /dev/null
+++ b/src/tool_sdecls.h
@@ -0,0 +1,153 @@
+#ifndef HEADER_CURL_TOOL_SDECLS_H
+#define HEADER_CURL_TOOL_SDECLS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+#ifdef USE_METALINK
+# include <metalink/metalink.h>
+#endif /* USE_METALINK */
+
+/*
+ * OutStruct variables keep track of information relative to curl's
+ * output writing, which may take place to a standard stream or a file.
+ *
+ * 'filename' member is either a pointer to a file name string or NULL
+ * when dealing with a standard stream.
+ *
+ * 'alloc_filename' member is TRUE when string pointed by 'filename' has been
+ * dynamically allocated and 'belongs' to this OutStruct, otherwise FALSE.
+ *
+ * 'is_cd_filename' member is TRUE when string pointed by 'filename' has been
+ * set using a server-specified Content-Disposition filename, otherwise FALSE.
+ *
+ * 's_isreg' member is TRUE when output goes to a regular file, this also
+ * implies that output is 'seekable' and 'appendable' and also that member
+ * 'filename' points to file name's string. For any standard stream member
+ * 's_isreg' will be FALSE.
+ *
+ * 'fopened' member is TRUE when output goes to a regular file and it
+ * has been fopen'ed, requiring it to be closed later on. In any other
+ * case this is FALSE.
+ *
+ * 'stream' member is a pointer to a stream controlling object as returned
+ * from a 'fopen' call or a standard stream.
+ *
+ * 'config' member is a pointer to associated 'Configurable' struct.
+ *
+ * 'bytes' member represents amount written so far.
+ *
+ * 'init' member holds original file size or offset at which truncation is
+ * taking place. Always zero unless appending to a non-empty regular file.
+ *
+ * 'metalink_parser' member is a pointer to Metalink XML parser
+ * context.
+ */
+
+struct OutStruct {
+ char *filename;
+ bool alloc_filename;
+ bool is_cd_filename;
+ bool s_isreg;
+ bool fopened;
+ FILE *stream;
+ struct Configurable *config;
+ curl_off_t bytes;
+ curl_off_t init;
+#ifdef USE_METALINK
+ metalink_parser_context_t *metalink_parser;
+#endif /* USE_METALINK */
+};
+
+
+/*
+ * InStruct variables keep track of information relative to curl's
+ * input reading, which may take place from stdin or from some file.
+ *
+ * 'fd' member is either 'stdin' file descriptor number STDIN_FILENO
+ * or a file descriptor as returned from an 'open' call for some file.
+ *
+ * 'config' member is a pointer to associated 'Configurable' struct.
+ */
+
+struct InStruct {
+ int fd;
+ struct Configurable *config;
+};
+
+
+/*
+ * A linked list of these 'getout' nodes contain URL's to fetch,
+ * as well as information relative to where URL contents should
+ * be stored or which file should be uploaded.
+ */
+
+struct getout {
+ struct getout *next; /* next one */
+ char *url; /* the URL we deal with */
+ char *outfile; /* where to store the output */
+ char *infile; /* file to upload, if GETOUT_UPLOAD is set */
+ int flags; /* options - composed of GETOUT_* bits */
+};
+
+#define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */
+#define GETOUT_URL (1<<1) /* set when URL is deemed done */
+#define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
+#define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
+#define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
+#define GETOUT_METALINK (1<<5) /* set when Metalink download */
+
+/*
+ * 'trace' enumeration represents curl's output look'n feel possibilities.
+ */
+
+typedef enum {
+ TRACE_NONE, /* no trace/verbose output at all */
+ TRACE_BIN, /* tcpdump inspired look */
+ TRACE_ASCII, /* like *BIN but without the hex output */
+ TRACE_PLAIN /* -v/--verbose type */
+} trace;
+
+
+/*
+ * 'HttpReq' enumeration represents HTTP request types.
+ */
+
+typedef enum {
+ HTTPREQ_UNSPEC, /* first in list */
+ HTTPREQ_GET,
+ HTTPREQ_HEAD,
+ HTTPREQ_POST,
+ HTTPREQ_SIMPLEPOST,
+ HTTPREQ_CUSTOM,
+ HTTPREQ_LAST /* last in list */
+} HttpReq;
+
+
+/*
+ * Complete struct declarations which have Configurable struct members,
+ * just in case this header is directly included in some source file.
+ */
+
+#include "tool_cfgable.h"
+
+#endif /* HEADER_CURL_TOOL_SDECLS_H */
+
diff --git a/src/tool_setopt.c b/src/tool_setopt.c
new file mode 100644
index 000000000..9aefc21d5
--- /dev/null
+++ b/src/tool_setopt.c
@@ -0,0 +1,528 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifndef CURL_DISABLE_LIBCURL_OPTION
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
+#include "curlx.h"
+
+#include "tool_cfgable.h"
+#include "tool_easysrc.h"
+#include "tool_setopt.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+/* Lookup tables for converting setopt values back to symbols */
+/* For enums, values may be in any order. */
+/* For bit masks, put combinations first, then single bits, */
+/* and finally any "NONE" value. */
+
+#define NV(e) {#e, e}
+#define NVEND {NULL, 0} /* sentinel to mark end of list */
+
+const NameValue setopt_nv_CURLPROXY[] = {
+ NV(CURLPROXY_HTTP),
+ NV(CURLPROXY_HTTP_1_0),
+ NV(CURLPROXY_SOCKS4),
+ NV(CURLPROXY_SOCKS5),
+ NV(CURLPROXY_SOCKS4A),
+ NV(CURLPROXY_SOCKS5_HOSTNAME),
+ NVEND,
+};
+
+const NameValueUnsigned setopt_nv_CURLAUTH[] = {
+ NV(CURLAUTH_ANY), /* combination */
+ NV(CURLAUTH_ANYSAFE), /* combination */
+ NV(CURLAUTH_BASIC),
+ NV(CURLAUTH_DIGEST),
+ NV(CURLAUTH_GSSNEGOTIATE),
+ NV(CURLAUTH_NTLM),
+ NV(CURLAUTH_DIGEST_IE),
+ NV(CURLAUTH_NTLM_WB),
+ NV(CURLAUTH_ONLY),
+ NV(CURLAUTH_NONE),
+ NVEND,
+};
+
+const NameValue setopt_nv_CURL_HTTP_VERSION[] = {
+ NV(CURL_HTTP_VERSION_NONE),
+ NV(CURL_HTTP_VERSION_1_0),
+ NV(CURL_HTTP_VERSION_1_1),
+ NVEND,
+};
+
+const NameValue setopt_nv_CURL_SSLVERSION[] = {
+ NV(CURL_SSLVERSION_DEFAULT),
+ NV(CURL_SSLVERSION_TLSv1),
+ NV(CURL_SSLVERSION_SSLv2),
+ NV(CURL_SSLVERSION_SSLv3),
+ NVEND,
+};
+
+const NameValue setopt_nv_CURL_TIMECOND[] = {
+ NV(CURL_TIMECOND_IFMODSINCE),
+ NV(CURL_TIMECOND_IFUNMODSINCE),
+ NV(CURL_TIMECOND_LASTMOD),
+ NV(CURL_TIMECOND_NONE),
+ NVEND,
+};
+
+const NameValue setopt_nv_CURLFTPSSL_CCC[] = {
+ NV(CURLFTPSSL_CCC_NONE),
+ NV(CURLFTPSSL_CCC_PASSIVE),
+ NV(CURLFTPSSL_CCC_ACTIVE),
+ NVEND,
+};
+
+/* These mappings essentially triplicated - see
+ * tool_libinfo.c and tool_paramhlp.c */
+const NameValue setopt_nv_CURLPROTO[] = {
+ NV(CURLPROTO_ALL), /* combination */
+ NV(CURLPROTO_DICT),
+ NV(CURLPROTO_FILE),
+ NV(CURLPROTO_FTP),
+ NV(CURLPROTO_FTPS),
+ NV(CURLPROTO_GOPHER),
+ NV(CURLPROTO_HTTP),
+ NV(CURLPROTO_HTTPS),
+ NV(CURLPROTO_IMAP),
+ NV(CURLPROTO_IMAPS),
+ NV(CURLPROTO_LDAP),
+ NV(CURLPROTO_LDAPS),
+ NV(CURLPROTO_POP3),
+ NV(CURLPROTO_POP3S),
+ NV(CURLPROTO_RTSP),
+ NV(CURLPROTO_SCP),
+ NV(CURLPROTO_SFTP),
+ NV(CURLPROTO_SMTP),
+ NV(CURLPROTO_SMTPS),
+ NV(CURLPROTO_TELNET),
+ NV(CURLPROTO_TFTP),
+ NVEND,
+};
+
+/* Format and add code; jump to nomem on malloc error */
+#define ADD(args) do { \
+ ret = easysrc_add args; \
+ if(ret) \
+ goto nomem; \
+} WHILE_FALSE
+#define ADDF(args) do { \
+ ret = easysrc_addf args; \
+ if(ret) \
+ goto nomem; \
+} WHILE_FALSE
+
+#define DECL0(s) ADD((&easysrc_decl, s))
+#define DECL1(f,a) ADDF((&easysrc_decl, f,a))
+
+#define DATA0(s) ADD((&easysrc_data, s))
+#define DATA1(f,a) ADDF((&easysrc_data, f,a))
+#define DATA2(f,a,b) ADDF((&easysrc_data, f,a,b))
+#define DATA3(f,a,b,c) ADDF((&easysrc_data, f,a,b,c))
+
+#define CODE0(s) ADD((&easysrc_code, s))
+#define CODE1(f,a) ADDF((&easysrc_code, f,a))
+#define CODE2(f,a,b) ADDF((&easysrc_code, f,a,b))
+#define CODE3(f,a,b,c) ADDF((&easysrc_code, f,a,b,c))
+
+#define CLEAN0(s) ADD((&easysrc_clean, s))
+#define CLEAN1(f,a) ADDF((&easysrc_clean, f,a))
+
+#define REM0(s) ADD((&easysrc_toohard, s))
+#define REM1(f,a) ADDF((&easysrc_toohard, f,a))
+#define REM2(f,a,b) ADDF((&easysrc_toohard, f,a,b))
+
+/* Escape string to C string syntax. Return NULL if out of memory.
+ * Is this correct for those wacky EBCDIC guys? */
+static char *c_escape(const char *str)
+{
+ size_t len = 0;
+ const char *s;
+ unsigned char c;
+ char *escaped, *e;
+ /* Allocate space based on worst-case */
+ len = strlen(str);
+ escaped = malloc(4 * len + 1);
+ if(!escaped)
+ return NULL;
+
+ e = escaped;
+ for(s=str; (c=*s) != '\0'; s++) {
+ if(c=='\n') {
+ strcpy(e, "\\n");
+ e += 2;
+ }
+ else if(c=='\r') {
+ strcpy(e, "\\r");
+ e += 2;
+ }
+ else if(c=='\t') {
+ strcpy(e, "\\t");
+ e += 2;
+ }
+ else if(c=='\\') {
+ strcpy(e, "\\\\");
+ e += 2;
+ }
+ else if(c=='"') {
+ strcpy(e, "\\\"");
+ e += 2;
+ }
+ else if(! isprint(c)) {
+ sprintf(e, "\\%03o", c);
+ e += 4;
+ }
+ else
+ *e++ = c;
+ }
+ *e = '\0';
+ return escaped;
+}
+
+/* setopt wrapper for enum types */
+CURLcode tool_setopt_enum(CURL *curl, struct Configurable *config,
+ const char *name, CURLoption tag,
+ const NameValue *nvlist, long lval)
+{
+ CURLcode ret = CURLE_OK;
+ bool skip = FALSE;
+
+ ret = curl_easy_setopt(curl, tag, lval);
+ if(!lval)
+ skip = TRUE;
+
+ if(config->libcurl && !skip && !ret) {
+ /* we only use this for real if --libcurl was used */
+ const NameValue *nv = NULL;
+ for(nv=nvlist; nv->name; nv++) {
+ if(nv->value == lval) break; /* found it */
+ }
+ if(! nv->name) {
+ /* If no definition was found, output an explicit value.
+ * This could happen if new values are defined and used
+ * but the NameValue list is not updated. */
+ CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval);
+ }
+ else {
+ CODE2("curl_easy_setopt(hnd, %s, (long)%s);", name, nv->name);
+ }
+ }
+
+ nomem:
+ return ret;
+}
+
+/* setopt wrapper for flags */
+CURLcode tool_setopt_flags(CURL *curl, struct Configurable *config,
+ const char *name, CURLoption tag,
+ const NameValue *nvlist, long lval)
+{
+ CURLcode ret = CURLE_OK;
+ bool skip = FALSE;
+
+ ret = curl_easy_setopt(curl, tag, lval);
+ if(!lval)
+ skip = TRUE;
+
+ if(config->libcurl && !skip && !ret) {
+ /* we only use this for real if --libcurl was used */
+ char preamble[80]; /* should accommodate any symbol name */
+ long rest = lval; /* bits not handled yet */
+ const NameValue *nv = NULL;
+ snprintf(preamble, sizeof(preamble),
+ "curl_easy_setopt(hnd, %s, ", name);
+ for(nv=nvlist; nv->name; nv++) {
+ if((nv->value & ~ rest) == 0) {
+ /* all value flags contained in rest */
+ rest &= ~ nv->value; /* remove bits handled here */
+ CODE3("%s(long)%s%s",
+ preamble, nv->name, rest ? " |" : ");");
+ if(!rest)
+ break; /* handled them all */
+ /* replace with all spaces for continuation line */
+ sprintf(preamble, "%*s", strlen(preamble), "");
+ }
+ }
+ /* If any bits have no definition, output an explicit value.
+ * This could happen if new bits are defined and used
+ * but the NameValue list is not updated. */
+ if(rest)
+ CODE2("%s%ldL);", preamble, rest);
+ }
+
+ nomem:
+ return ret;
+}
+
+/* setopt wrapper for bitmasks */
+CURLcode tool_setopt_bitmask(CURL *curl, struct Configurable *config,
+ const char *name, CURLoption tag,
+ const NameValueUnsigned *nvlist,
+ long lval)
+{
+ CURLcode ret = CURLE_OK;
+ bool skip = FALSE;
+
+ ret = curl_easy_setopt(curl, tag, lval);
+ if(!lval)
+ skip = TRUE;
+
+ if(config->libcurl && !skip && !ret) {
+ /* we only use this for real if --libcurl was used */
+ char preamble[80];
+ unsigned long rest = (unsigned long)lval;
+ const NameValueUnsigned *nv = NULL;
+ snprintf(preamble, sizeof(preamble),
+ "curl_easy_setopt(hnd, %s, ", name);
+ for(nv=nvlist; nv->name; nv++) {
+ if((nv->value & ~ rest) == 0) {
+ /* all value flags contained in rest */
+ rest &= ~ nv->value; /* remove bits handled here */
+ CODE3("%s(long)%s%s",
+ preamble, nv->name, rest ? " |" : ");");
+ if(!rest)
+ break; /* handled them all */
+ /* replace with all spaces for continuation line */
+ sprintf(preamble, "%*s", strlen(preamble), "");
+ }
+ }
+ /* If any bits have no definition, output an explicit value.
+ * This could happen if new bits are defined and used
+ * but the NameValue list is not updated. */
+ if(rest)
+ CODE2("%s%luUL);", preamble, rest);
+ }
+
+ nomem:
+ return ret;
+}
+
+/* setopt wrapper for CURLOPT_HTTPPOST */
+CURLcode tool_setopt_httppost(CURL *curl, struct Configurable *config,
+ const char *name, CURLoption tag,
+ struct curl_httppost *post)
+{
+ CURLcode ret = CURLE_OK;
+ char *escaped = NULL;
+ bool skip = FALSE;
+
+ ret = curl_easy_setopt(curl, tag, post);
+ if(!post)
+ skip = TRUE;
+
+ if(config->libcurl && !skip && !ret) {
+ struct curl_httppost *pp, *p;
+ int i;
+ /* May use several httppost lists, if multiple POST actions */
+ i = ++ easysrc_form_count;
+ DECL1("struct curl_httppost *post%d;", i);
+ DATA1("post%d = NULL;", i);
+ CLEAN1("curl_formfree(post%d);", i);
+ CLEAN1("post%d = NULL;", i);
+ if(i == 1)
+ DECL0("struct curl_httppost *postend;");
+ DATA0("postend = NULL;");
+ for(p=post; p; p=p->next) {
+ DATA1("curl_formadd(&post%d, &postend,", i);
+ DATA1(" CURLFORM_COPYNAME, \"%s\",", p->name);
+ for(pp=p; pp; pp=pp->more) {
+ /* May be several files uploaded for one name;
+ * these are linked through the 'more' pointer */
+ Curl_safefree(escaped);
+ escaped = c_escape(pp->contents);
+ if(!escaped) {
+ ret = CURLE_OUT_OF_MEMORY;
+ goto nomem;
+ }
+ if(pp->flags & HTTPPOST_FILENAME) {
+ /* file upload as for -F @filename */
+ DATA1(" CURLFORM_FILE, \"%s\",", escaped);
+ }
+ else if(pp->flags & HTTPPOST_READFILE) {
+ /* content from file as for -F <filename */
+ DATA1(" CURLFORM_FILECONTENT, \"%s\",", escaped);
+ }
+ else
+ DATA1(" CURLFORM_COPYCONTENTS, \"%s\",", escaped);
+ if(pp->showfilename) {
+ Curl_safefree(escaped);
+ escaped = c_escape(pp->showfilename);
+ if(!escaped) {
+ ret = CURLE_OUT_OF_MEMORY;
+ goto nomem;
+ }
+ DATA1(" CURLFORM_FILENAME, \"%s\",", escaped);
+ }
+ if(pp->contenttype) {
+ Curl_safefree(escaped);
+ escaped = c_escape(pp->contenttype);
+ if(!escaped) {
+ ret = CURLE_OUT_OF_MEMORY;
+ goto nomem;
+ }
+ DATA1(" CURLFORM_CONTENTTYPE, \"%s\",", escaped);
+ }
+ }
+ DATA0(" CURLFORM_END);");
+ }
+ CODE2("curl_easy_setopt(hnd, %s, post%d);", name, i);
+ }
+
+ nomem:
+ Curl_safefree(escaped);
+ return ret;
+}
+
+/* setopt wrapper for curl_slist options */
+CURLcode tool_setopt_slist(CURL *curl, struct Configurable *config,
+ const char *name, CURLoption tag,
+ struct curl_slist *list)
+{
+ CURLcode ret = CURLE_OK;
+ char *escaped = NULL;
+ bool skip = FALSE;
+
+ ret = curl_easy_setopt(curl, tag, list);
+ if(!list)
+ skip = TRUE;
+
+ if(config->libcurl && !skip && !ret) {
+ struct curl_slist *s;
+ int i;
+ /* May need several slist variables, so invent name */
+ i = ++ easysrc_slist_count;
+ DECL1("struct curl_slist *slist%d;", i);
+ DATA1("slist%d = NULL;", i);
+ CLEAN1("curl_slist_free_all(slist%d);", i);
+ CLEAN1("slist%d = NULL;", i);
+ for(s=list; s; s=s->next) {
+ Curl_safefree(escaped);
+ escaped = c_escape(s->data);
+ if(!escaped) {
+ ret = CURLE_OUT_OF_MEMORY;
+ goto nomem;
+ }
+ DATA3("slist%d = curl_slist_append(slist%d, \"%s\");", i, i, escaped);
+ }
+ CODE2("curl_easy_setopt(hnd, %s, slist%d);", name, i);
+ }
+
+ nomem:
+ Curl_safefree(escaped);
+ return ret;
+}
+
+/* generic setopt wrapper for all other options.
+ * Some type information is encoded in the tag value. */
+CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config,
+ const char *name, CURLoption tag, ...)
+{
+ va_list arg;
+ char buf[256];
+ const char *value = NULL;
+ bool remark = FALSE;
+ bool skip = FALSE;
+ bool escape = FALSE;
+ char *escaped = NULL;
+ CURLcode ret = CURLE_OK;
+
+ va_start(arg, tag);
+
+ if(tag < CURLOPTTYPE_OBJECTPOINT) {
+ /* Value is expected to be a long */
+ long lval = va_arg(arg, long);
+ snprintf(buf, sizeof(buf), "%ldL", lval);
+ value = buf;
+ ret = curl_easy_setopt(curl, tag, lval);
+ if(!lval)
+ skip = TRUE;
+ }
+ else if(tag < CURLOPTTYPE_OFF_T) {
+ /* Value is some sort of object pointer */
+ void *pval = va_arg(arg, void *);
+
+ /* function pointers are never printable */
+ if(tag >= CURLOPTTYPE_FUNCTIONPOINT) {
+ if(pval) {
+ value = "functionpointer";
+ remark = TRUE;
+ }
+ else
+ skip = TRUE;
+ }
+
+ else if(pval && str) {
+ value = (char *)pval;
+ escape = TRUE;
+ }
+ else if(pval) {
+ value = "objectpointer";
+ remark = TRUE;
+ }
+ else
+ skip = TRUE;
+
+ ret = curl_easy_setopt(curl, tag, pval);
+
+ }
+ else {
+ /* Value is expected to be curl_off_t */
+ curl_off_t oval = va_arg(arg, curl_off_t);
+ snprintf(buf, sizeof(buf),
+ "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval);
+ value = buf;
+ ret = curl_easy_setopt(curl, tag, oval);
+
+ if(!oval)
+ skip = TRUE;
+ }
+
+ va_end(arg);
+
+ if(config->libcurl && !skip && !ret) {
+ /* we only use this for real if --libcurl was used */
+
+ if(remark)
+ REM2("%s set to a %s", name, value);
+ else {
+ if(escape) {
+ escaped = c_escape(value);
+ if(!escaped) {
+ ret = CURLE_OUT_OF_MEMORY;
+ goto nomem;
+ }
+ CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped);
+ }
+ else
+ CODE2("curl_easy_setopt(hnd, %s, %s);", name, value);
+ }
+ }
+
+ nomem:
+ Curl_safefree(escaped);
+ return ret;
+}
+
+#endif /* CURL_DISABLE_LIBCURL_OPTION */
diff --git a/src/tool_setopt.h b/src/tool_setopt.h
new file mode 100644
index 000000000..d107756b4
--- /dev/null
+++ b/src/tool_setopt.h
@@ -0,0 +1,144 @@
+#ifndef HEADER_CURL_TOOL_SETOPT_H
+#define HEADER_CURL_TOOL_SETOPT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+/*
+ * Macros used in operate()
+ */
+
+#define SETOPT_CHECK(v) do { \
+ res = (v); \
+ if(res) \
+ goto show_error; \
+} WHILE_FALSE
+
+#ifndef CURL_DISABLE_LIBCURL_OPTION
+
+/* Associate symbolic names with option values */
+typedef struct {
+ const char *name;
+ long value;
+} NameValue;
+
+typedef struct {
+ const char *name;
+ unsigned long value;
+} NameValueUnsigned;
+
+extern const NameValue setopt_nv_CURLPROXY[];
+extern const NameValue setopt_nv_CURL_HTTP_VERSION[];
+extern const NameValue setopt_nv_CURL_SSLVERSION[];
+extern const NameValue setopt_nv_CURL_TIMECOND[];
+extern const NameValue setopt_nv_CURLFTPSSL_CCC[];
+extern const NameValue setopt_nv_CURLPROTO[];
+extern const NameValueUnsigned setopt_nv_CURLAUTH[];
+
+/* Map options to NameValue sets */
+#define setopt_nv_CURLOPT_HTTP_VERSION setopt_nv_CURL_HTTP_VERSION
+#define setopt_nv_CURLOPT_HTTPAUTH setopt_nv_CURLAUTH
+#define setopt_nv_CURLOPT_SSLVERSION setopt_nv_CURL_SSLVERSION
+#define setopt_nv_CURLOPT_TIMECONDITION setopt_nv_CURL_TIMECOND
+#define setopt_nv_CURLOPT_FTP_SSL_CCC setopt_nv_CURLFTPSSL_CCC
+#define setopt_nv_CURLOPT_PROTOCOLS setopt_nv_CURLPROTO
+#define setopt_nv_CURLOPT_REDIR_PROTOCOLS setopt_nv_CURLPROTO
+#define setopt_nv_CURLOPT_PROXYTYPE setopt_nv_CURLPROXY
+#define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH
+
+/* Intercept setopt calls for --libcurl */
+
+CURLcode tool_setopt_enum(CURL *curl, struct Configurable *config,
+ const char *name, CURLoption tag,
+ const NameValue *nv, long lval);
+CURLcode tool_setopt_flags(CURL *curl, struct Configurable *config,
+ const char *name, CURLoption tag,
+ const NameValue *nv, long lval);
+CURLcode tool_setopt_bitmask(CURL *curl, struct Configurable *config,
+ const char *name, CURLoption tag,
+ const NameValueUnsigned *nv, long lval);
+CURLcode tool_setopt_httppost(CURL *curl, struct Configurable *config,
+ const char *name, CURLoption tag,
+ struct curl_httppost *httppost);
+CURLcode tool_setopt_slist(CURL *curl, struct Configurable *config,
+ const char *name, CURLoption tag,
+ struct curl_slist *list);
+CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config,
+ const char *name, CURLoption tag, ...);
+
+#define my_setopt(x,y,z) \
+ SETOPT_CHECK(tool_setopt(x, FALSE, config, #y, y, z))
+
+#define my_setopt_str(x,y,z) \
+ SETOPT_CHECK(tool_setopt(x, TRUE, config, #y, y, z))
+
+#define my_setopt_enum(x,y,z) \
+ SETOPT_CHECK(tool_setopt_enum(x, config, #y, y, setopt_nv_ ## y, z))
+
+#define my_setopt_flags(x,y,z) \
+ SETOPT_CHECK(tool_setopt_flags(x, config, #y, y, setopt_nv_ ## y, z))
+
+#define my_setopt_bitmask(x,y,z) \
+ SETOPT_CHECK(tool_setopt_bitmask(x, config, #y, y, setopt_nv_ ## y, z))
+
+#define my_setopt_httppost(x,y,z) \
+ SETOPT_CHECK(tool_setopt_httppost(x, config, #y, y, z))
+
+#define my_setopt_slist(x,y,z) \
+ SETOPT_CHECK(tool_setopt_slist(x, config, #y, y, z))
+
+#define res_setopt(x,y,z) tool_setopt(x, FALSE, config, #y, y, z)
+
+#define res_setopt_str(x,y,z) tool_setopt(x, TRUE, config, #y, y, z)
+
+#else /* CURL_DISABLE_LIBCURL_OPTION */
+
+/* No --libcurl, so pass options directly to library */
+
+#define my_setopt(x,y,z) \
+ SETOPT_CHECK(curl_easy_setopt(x, y, z))
+
+#define my_setopt_str(x,y,z) \
+ SETOPT_CHECK(curl_easy_setopt(x, y, z))
+
+#define my_setopt_enum(x,y,z) \
+ SETOPT_CHECK(curl_easy_setopt(x, y, z))
+
+#define my_setopt_flags(x,y,z) \
+ SETOPT_CHECK(curl_easy_setopt(x, y, z))
+
+#define my_setopt_bitmask(x,y,z) \
+ SETOPT_CHECK(curl_easy_setopt(x, y, z))
+
+#define my_setopt_httppost(x,y,z) \
+ SETOPT_CHECK(curl_easy_setopt(x, y, z))
+
+#define my_setopt_slist(x,y,z) \
+ SETOPT_CHECK(curl_easy_setopt(x, y, z))
+
+#define res_setopt(x,y,z) curl_easy_setopt(x,y,z)
+
+#define res_setopt_str(x,y,z) curl_easy_setopt(x,y,z)
+
+#endif /* CURL_DISABLE_LIBCURL_OPTION */
+
+#endif /* HEADER_CURL_TOOL_SETOPT_H */
diff --git a/src/tool_setup.h b/src/tool_setup.h
new file mode 100644
index 000000000..ed3849ba3
--- /dev/null
+++ b/src/tool_setup.h
@@ -0,0 +1,75 @@
+#ifndef HEADER_CURL_TOOL_SETUP_H
+#define HEADER_CURL_TOOL_SETUP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#define CURL_NO_OLDIES
+
+/*
+ * setup.h may define preprocessor macros such as _FILE_OFFSET_BITS and
+ * _LARGE_FILES in order to support files larger than 2 GB. On platforms
+ * where this happens it is mandatory that these macros are defined before
+ * any system header file is included, otherwise file handling function
+ * prototypes will be misdeclared and curl tool may not build properly;
+ * therefore we must include setup.h before curl.h when building curl.
+ */
+
+#include "setup.h" /* from the lib directory */
+
+/*
+ * curl tool certainly uses libcurl's external interface.
+ */
+
+#include <curl/curl.h> /* external interface */
+
+/*
+ * Platform specific stuff.
+ */
+
+#if defined(macintosh) && defined(__MRC__)
+# define main(x,y) curl_main(x,y)
+#endif
+
+#ifdef TPF
+# undef select
+ /* change which select is used for the curl command line tool */
+# define select(a,b,c,d,e) tpf_select_bsd(a,b,c,d,e)
+ /* and turn off the progress meter */
+# define CONF_DEFAULT (0|CONF_NOPROGRESS)
+#endif
+
+#ifndef OS
+# define OS "unknown"
+#endif
+
+#ifndef UNPRINTABLE_CHAR
+ /* define what to use for unprintable characters */
+# define UNPRINTABLE_CHAR '.'
+#endif
+
+#ifndef HAVE_STRDUP
+# include "strdup.h"
+# define strdup(ptr) curlx_strdup(ptr)
+#endif
+
+#endif /* HEADER_CURL_TOOL_SETUP_H */
+
diff --git a/src/tool_sleep.c b/src/tool_sleep.c
new file mode 100644
index 000000000..835484025
--- /dev/null
+++ b/src/tool_sleep.c
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+#elif defined(HAVE_POLL_H)
+# include <poll.h>
+#endif
+
+#ifdef MSDOS
+# include <dos.h>
+#endif
+
+#include "tool_sleep.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+void tool_go_sleep(long ms)
+{
+#if defined(MSDOS)
+ delay(ms);
+#elif defined(WIN32)
+ Sleep(ms);
+#elif defined(HAVE_POLL_FINE)
+ poll((void *)0, 0, (int)ms);
+#else
+ struct timeval timeout;
+ timeout.tv_sec = ms / 1000L;
+ ms = ms % 1000L;
+ timeout.tv_usec = ms * 1000L;
+ select(0, NULL, NULL, NULL, &timeout);
+#endif
+}
+
diff --git a/src/tool_sleep.h b/src/tool_sleep.h
new file mode 100644
index 000000000..115a4e404
--- /dev/null
+++ b/src/tool_sleep.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TOOL_SLEEP_H
+#define HEADER_CURL_TOOL_SLEEP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+void tool_go_sleep(long ms);
+
+#endif /* HEADER_CURL_TOOL_SLEEP_H */
+
diff --git a/src/tool_urlglob.c b/src/tool_urlglob.c
new file mode 100644
index 000000000..2821d008d
--- /dev/null
+++ b/src/tool_urlglob.c
@@ -0,0 +1,614 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
+#include <curl/mprintf.h>
+
+#include "tool_urlglob.h"
+#include "tool_vms.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+typedef enum {
+ GLOB_OK,
+ GLOB_NO_MEM,
+ GLOB_ERROR
+} GlobCode;
+
+/*
+ * glob_word()
+ *
+ * Input a full globbed string, set the forth argument to the amount of
+ * strings we get out of this. Return GlobCode.
+ */
+static GlobCode glob_word(URLGlob *, /* object anchor */
+ char *, /* globbed string */
+ size_t, /* position */
+ int *); /* returned number of strings */
+
+static GlobCode glob_set(URLGlob *glob, char *pattern,
+ size_t pos, int *amount)
+{
+ /* processes a set expression with the point behind the opening '{'
+ ','-separated elements are collected until the next closing '}'
+ */
+ URLPattern *pat;
+ GlobCode res;
+ bool done = FALSE;
+ char* buf = glob->glob_buffer;
+
+ pat = &glob->pattern[glob->size / 2];
+ /* patterns 0,1,2,... correspond to size=1,3,5,... */
+ pat->type = UPTSet;
+ pat->content.Set.size = 0;
+ pat->content.Set.ptr_s = 0;
+ pat->content.Set.elements = NULL;
+
+ if(++glob->size > (GLOB_PATTERN_NUM*2)) {
+ snprintf(glob->errormsg, sizeof(glob->errormsg), "too many globs used\n");
+ return GLOB_ERROR;
+ }
+
+ while(!done) {
+ switch (*pattern) {
+ case '\0': /* URL ended while set was still open */
+ snprintf(glob->errormsg, sizeof(glob->errormsg),
+ "unmatched brace at pos %zu\n", pos);
+ return GLOB_ERROR;
+
+ case '{':
+ case '[': /* no nested expressions at this time */
+ snprintf(glob->errormsg, sizeof(glob->errormsg),
+ "nested braces not supported at pos %zu\n", pos);
+ return GLOB_ERROR;
+
+ case ',':
+ case '}': /* set element completed */
+ *buf = '\0';
+ if(pat->content.Set.elements) {
+ char **new_arr = realloc(pat->content.Set.elements,
+ (pat->content.Set.size + 1) * sizeof(char*));
+ if(!new_arr) {
+ short elem;
+ for(elem = 0; elem < pat->content.Set.size; elem++)
+ Curl_safefree(pat->content.Set.elements[elem]);
+ Curl_safefree(pat->content.Set.elements);
+ pat->content.Set.ptr_s = 0;
+ pat->content.Set.size = 0;
+ }
+ pat->content.Set.elements = new_arr;
+ }
+ else
+ pat->content.Set.elements = malloc(sizeof(char*));
+ if(!pat->content.Set.elements) {
+ snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n");
+ return GLOB_NO_MEM;
+ }
+ pat->content.Set.elements[pat->content.Set.size] =
+ strdup(glob->glob_buffer);
+ if(!pat->content.Set.elements[pat->content.Set.size]) {
+ short elem;
+ for(elem = 0; elem < pat->content.Set.size; elem++)
+ Curl_safefree(pat->content.Set.elements[elem]);
+ Curl_safefree(pat->content.Set.elements);
+ pat->content.Set.ptr_s = 0;
+ pat->content.Set.size = 0;
+ snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n");
+ return GLOB_NO_MEM;
+ }
+ ++pat->content.Set.size;
+
+ if(*pattern == '}') {
+ /* entire set pattern completed */
+ int wordamount;
+
+ /* always check for a literal (may be "") between patterns */
+ res = glob_word(glob, ++pattern, ++pos, &wordamount);
+ if(res) {
+ short elem;
+ for(elem = 0; elem < pat->content.Set.size; elem++)
+ Curl_safefree(pat->content.Set.elements[elem]);
+ Curl_safefree(pat->content.Set.elements);
+ pat->content.Set.ptr_s = 0;
+ pat->content.Set.size = 0;
+ return res;
+ }
+
+ *amount = pat->content.Set.size * wordamount;
+
+ done = TRUE;
+ continue;
+ }
+
+ buf = glob->glob_buffer;
+ ++pattern;
+ ++pos;
+ break;
+
+ case ']': /* illegal closing bracket */
+ snprintf(glob->errormsg, sizeof(glob->errormsg),
+ "illegal pattern at pos %zu\n", pos);
+ return GLOB_ERROR;
+
+ case '\\': /* escaped character, skip '\' */
+ if(pattern[1]) {
+ ++pattern;
+ ++pos;
+ }
+ /* intentional fallthrough */
+ default:
+ *buf++ = *pattern++; /* copy character to set element */
+ ++pos;
+ }
+ }
+ return GLOB_OK;
+}
+
+static GlobCode glob_range(URLGlob *glob, char *pattern,
+ size_t pos, int *amount)
+{
+ /* processes a range expression with the point behind the opening '['
+ - char range: e.g. "a-z]", "B-Q]"
+ - num range: e.g. "0-9]", "17-2000]"
+ - num range with leading zeros: e.g. "001-999]"
+ expression is checked for well-formedness and collected until the next ']'
+ */
+ URLPattern *pat;
+ char *c;
+ char sep;
+ char sep2;
+ int step;
+ int rc;
+ GlobCode res;
+ int wordamount = 1;
+
+ pat = &glob->pattern[glob->size / 2];
+ /* patterns 0,1,2,... correspond to size=1,3,5,... */
+ if(++glob->size > (GLOB_PATTERN_NUM*2)) {
+ snprintf(glob->errormsg, sizeof(glob->errormsg), "too many globs used\n");
+ return GLOB_ERROR;
+ }
+
+ if(ISALPHA(*pattern)) {
+ /* character range detected */
+ char min_c;
+ char max_c;
+
+ pat->type = UPTCharRange;
+
+ rc = sscanf(pattern, "%c-%c%c%d%c", &min_c, &max_c, &sep, &step, &sep2);
+
+ if((rc < 3) || (min_c >= max_c) || ((max_c - min_c) > ('z' - 'a'))) {
+ /* the pattern is not well-formed */
+ snprintf(glob->errormsg, sizeof(glob->errormsg),
+ "error: bad range specification after pos %zu\n", pos);
+ return GLOB_ERROR;
+ }
+
+ /* check the (first) separating character */
+ if((sep != ']') && (sep != ':')) {
+ snprintf(glob->errormsg, sizeof(glob->errormsg),
+ "error: unsupported character (%c) after range at pos %zu\n",
+ sep, pos);
+ return GLOB_ERROR;
+ }
+
+ /* if there was a ":[num]" thing, use that as step or else use 1 */
+ pat->content.CharRange.step =
+ ((sep == ':') && (rc == 5) && (sep2 == ']')) ? step : 1;
+
+ pat->content.CharRange.ptr_c = pat->content.CharRange.min_c = min_c;
+ pat->content.CharRange.max_c = max_c;
+ }
+ else if(ISDIGIT(*pattern)) {
+ /* numeric range detected */
+ int min_n;
+ int max_n;
+
+ pat->type = UPTNumRange;
+ pat->content.NumRange.padlength = 0;
+
+ rc = sscanf(pattern, "%d-%d%c%d%c", &min_n, &max_n, &sep, &step, &sep2);
+
+ if((rc < 2) || (min_n > max_n)) {
+ /* the pattern is not well-formed */
+ snprintf(glob->errormsg, sizeof(glob->errormsg),
+ "error: bad range specification after pos %zu\n", pos);
+ return GLOB_ERROR;
+ }
+ pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n;
+ pat->content.NumRange.max_n = max_n;
+
+ /* if there was a ":[num]" thing, use that as step or else use 1 */
+ pat->content.NumRange.step =
+ ((sep == ':') && (rc == 5) && (sep2 == ']')) ? step : 1;
+
+ if(*pattern == '0') {
+ /* leading zero specified */
+ c = pattern;
+ while(ISDIGIT(*c)) {
+ c++;
+ ++pat->content.NumRange.padlength; /* padding length is set for all
+ instances of this pattern */
+ }
+ }
+ }
+ else {
+ snprintf(glob->errormsg, sizeof(glob->errormsg),
+ "illegal character in range specification at pos %zu\n", pos);
+ return GLOB_ERROR;
+ }
+
+ c = (char*)strchr(pattern, ']'); /* continue after next ']' */
+ if(c)
+ c++;
+ else {
+ snprintf(glob->errormsg, sizeof(glob->errormsg), "missing ']'");
+ return GLOB_ERROR; /* missing ']' */
+ }
+
+ /* always check for a literal (may be "") between patterns */
+
+ res = glob_word(glob, c, pos + (c - pattern), &wordamount);
+ if(res == GLOB_ERROR) {
+ wordamount = 1;
+ res = GLOB_OK;
+ }
+
+ if(!res) {
+ if(pat->type == UPTCharRange)
+ *amount = wordamount * (pat->content.CharRange.max_c -
+ pat->content.CharRange.min_c + 1);
+ else
+ *amount = wordamount * (pat->content.NumRange.max_n -
+ pat->content.NumRange.min_n + 1);
+ }
+
+ return res; /* GLOB_OK or GLOB_NO_MEM */
+}
+
+static GlobCode glob_word(URLGlob *glob, char *pattern,
+ size_t pos, int *amount)
+{
+ /* processes a literal string component of a URL
+ special characters '{' and '[' branch to set/range processing functions
+ */
+ char* buf = glob->glob_buffer;
+ size_t litindex;
+ GlobCode res = GLOB_OK;
+
+ *amount = 1; /* default is one single string */
+
+ while(*pattern != '\0' && *pattern != '{' && *pattern != '[') {
+ if(*pattern == '}' || *pattern == ']') {
+ snprintf(glob->errormsg, sizeof(glob->errormsg),
+ "unmatched close brace/bracket at pos %zu\n", pos);
+ return GLOB_ERROR;
+ }
+
+ /* only allow \ to escape known "special letters" */
+ if(*pattern == '\\' &&
+ (*(pattern+1) == '{' || *(pattern+1) == '[' ||
+ *(pattern+1) == '}' || *(pattern+1) == ']') ) {
+
+ /* escape character, skip '\' */
+ ++pattern;
+ ++pos;
+ }
+ *buf++ = *pattern++; /* copy character to literal */
+ ++pos;
+ }
+ *buf = '\0';
+ litindex = glob->size / 2;
+ /* literals 0,1,2,... correspond to size=0,2,4,... */
+ glob->literal[litindex] = strdup(glob->glob_buffer);
+ if(!glob->literal[litindex]) {
+ snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n");
+ return GLOB_NO_MEM;
+ }
+ ++glob->size;
+
+ switch (*pattern) {
+ case '\0':
+ /* singular URL processed */
+ break;
+
+ case '{':
+ /* process set pattern */
+ res = glob_set(glob, ++pattern, ++pos, amount);
+ break;
+
+ case '[':
+ /* process range pattern */
+ res = glob_range(glob, ++pattern, ++pos, amount);
+ break;
+ }
+
+ if(res)
+ Curl_safefree(glob->literal[litindex]);
+
+ return res;
+}
+
+int glob_url(URLGlob** glob, char* url, int *urlnum, FILE *error)
+{
+ /*
+ * We can deal with any-size, just make a buffer with the same length
+ * as the specified URL!
+ */
+ URLGlob *glob_expand;
+ int amount;
+ char *glob_buffer;
+ GlobCode res;
+
+ *glob = NULL;
+
+ glob_buffer = malloc(strlen(url) + 1);
+ if(!glob_buffer)
+ return CURLE_OUT_OF_MEMORY;
+
+ glob_expand = calloc(1, sizeof(URLGlob));
+ if(!glob_expand) {
+ Curl_safefree(glob_buffer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ glob_expand->size = 0;
+ glob_expand->urllen = strlen(url);
+ glob_expand->glob_buffer = glob_buffer;
+ glob_expand->beenhere = 0;
+
+ res = glob_word(glob_expand, url, 1, &amount);
+ if(!res)
+ *urlnum = amount;
+ else {
+ if(error && glob_expand->errormsg[0]) {
+ /* send error description to the error-stream */
+ fprintf(error, "curl: (%d) [globbing] %s",
+ (res == GLOB_NO_MEM) ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT,
+ glob_expand->errormsg);
+ }
+ /* it failed, we cleanup */
+ Curl_safefree(glob_buffer);
+ Curl_safefree(glob_expand);
+ *urlnum = 1;
+ return (res == GLOB_NO_MEM) ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT;
+ }
+
+ *glob = glob_expand;
+ return CURLE_OK;
+}
+
+void glob_cleanup(URLGlob* glob)
+{
+ size_t i;
+ int elem;
+
+ for(i = glob->size - 1; i < glob->size; --i) {
+ if(!(i & 1)) { /* even indexes contain literals */
+ Curl_safefree(glob->literal[i/2]);
+ }
+ else { /* odd indexes contain sets or ranges */
+ if((glob->pattern[i/2].type == UPTSet) &&
+ (glob->pattern[i/2].content.Set.elements)) {
+ for(elem = glob->pattern[i/2].content.Set.size - 1;
+ elem >= 0;
+ --elem) {
+ Curl_safefree(glob->pattern[i/2].content.Set.elements[elem]);
+ }
+ Curl_safefree(glob->pattern[i/2].content.Set.elements);
+ }
+ }
+ }
+ Curl_safefree(glob->glob_buffer);
+ Curl_safefree(glob);
+}
+
+int glob_next_url(char **globbed, URLGlob *glob)
+{
+ URLPattern *pat;
+ char *lit;
+ size_t i;
+ size_t j;
+ size_t len;
+ size_t buflen = glob->urllen + 1;
+ char *buf = glob->glob_buffer;
+
+ *globbed = NULL;
+
+ if(!glob->beenhere)
+ glob->beenhere = 1;
+ else {
+ bool carry = TRUE;
+
+ /* implement a counter over the index ranges of all patterns,
+ starting with the rightmost pattern */
+ for(i = glob->size / 2 - 1; carry && (i < glob->size); --i) {
+ carry = FALSE;
+ pat = &glob->pattern[i];
+ switch (pat->type) {
+ case UPTSet:
+ if((pat->content.Set.elements) &&
+ (++pat->content.Set.ptr_s == pat->content.Set.size)) {
+ pat->content.Set.ptr_s = 0;
+ carry = TRUE;
+ }
+ break;
+ case UPTCharRange:
+ pat->content.CharRange.ptr_c = (char)(pat->content.CharRange.step +
+ (int)((unsigned char)pat->content.CharRange.ptr_c));
+ if(pat->content.CharRange.ptr_c > pat->content.CharRange.max_c) {
+ pat->content.CharRange.ptr_c = pat->content.CharRange.min_c;
+ carry = TRUE;
+ }
+ break;
+ case UPTNumRange:
+ pat->content.NumRange.ptr_n += pat->content.NumRange.step;
+ if(pat->content.NumRange.ptr_n > pat->content.NumRange.max_n) {
+ pat->content.NumRange.ptr_n = pat->content.NumRange.min_n;
+ carry = TRUE;
+ }
+ break;
+ default:
+ printf("internal error: invalid pattern type (%d)\n", (int)pat->type);
+ return CURLE_FAILED_INIT;
+ }
+ }
+ if(carry) { /* first pattern ptr has run into overflow, done! */
+ /* TODO: verify if this should actally return CURLE_OK. */
+ return CURLE_OK; /* CURLE_OK to match previous behavior */
+ }
+ }
+
+ for(j = 0; j < glob->size; ++j) {
+ if(!(j&1)) { /* every other term (j even) is a literal */
+ lit = glob->literal[j/2];
+ len = snprintf(buf, buflen, "%s", lit);
+ buf += len;
+ buflen -= len;
+ }
+ else { /* the rest (i odd) are patterns */
+ pat = &glob->pattern[j/2];
+ switch(pat->type) {
+ case UPTSet:
+ if(pat->content.Set.elements) {
+ len = strlen(pat->content.Set.elements[pat->content.Set.ptr_s]);
+ snprintf(buf, buflen, "%s",
+ pat->content.Set.elements[pat->content.Set.ptr_s]);
+ buf += len;
+ buflen -= len;
+ }
+ break;
+ case UPTCharRange:
+ *buf++ = pat->content.CharRange.ptr_c;
+ break;
+ case UPTNumRange:
+ len = snprintf(buf, buflen, "%0*d",
+ pat->content.NumRange.padlength,
+ pat->content.NumRange.ptr_n);
+ buf += len;
+ buflen -= len;
+ break;
+ default:
+ printf("internal error: invalid pattern type (%d)\n", (int)pat->type);
+ return CURLE_FAILED_INIT;
+ }
+ }
+ }
+ *buf = '\0';
+
+ *globbed = strdup(glob->glob_buffer);
+ if(!*globbed)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
+}
+
+int glob_match_url(char **result, char *filename, URLGlob *glob)
+{
+ char *target;
+ size_t allocsize;
+ char numbuf[18];
+ char *appendthis = NULL;
+ size_t appendlen = 0;
+ size_t stringlen = 0;
+
+ *result = NULL;
+
+ /* We cannot use the glob_buffer for storage here since the filename may
+ * be longer than the URL we use. We allocate a good start size, then
+ * we need to realloc in case of need.
+ */
+ allocsize = strlen(filename) + 1; /* make it at least one byte to store the
+ trailing zero */
+ target = malloc(allocsize);
+ if(!target)
+ return CURLE_OUT_OF_MEMORY;
+
+ while(*filename) {
+ if(*filename == '#' && ISDIGIT(filename[1])) {
+ unsigned long i;
+ char *ptr = filename;
+ unsigned long num = strtoul(&filename[1], &filename, 10);
+ i = num - 1UL;
+
+ if(num && (i <= glob->size / 2)) {
+ URLPattern pat = glob->pattern[i];
+ switch (pat.type) {
+ case UPTSet:
+ if(pat.content.Set.elements) {
+ appendthis = pat.content.Set.elements[pat.content.Set.ptr_s];
+ appendlen =
+ strlen(pat.content.Set.elements[pat.content.Set.ptr_s]);
+ }
+ break;
+ case UPTCharRange:
+ numbuf[0] = pat.content.CharRange.ptr_c;
+ numbuf[1] = 0;
+ appendthis = numbuf;
+ appendlen = 1;
+ break;
+ case UPTNumRange:
+ snprintf(numbuf, sizeof(numbuf), "%0*d",
+ pat.content.NumRange.padlength,
+ pat.content.NumRange.ptr_n);
+ appendthis = numbuf;
+ appendlen = strlen(numbuf);
+ break;
+ default:
+ printf("internal error: invalid pattern type (%d)\n",
+ (int)pat.type);
+ Curl_safefree(target);
+ return CURLE_FAILED_INIT;
+ }
+ }
+ else {
+ /* #[num] out of range, use the #[num] in the output */
+ filename = ptr;
+ appendthis = filename++;
+ appendlen = 1;
+ }
+ }
+ else {
+ appendthis = filename++;
+ appendlen = 1;
+ }
+ if(appendlen + stringlen >= allocsize) {
+ char *newstr;
+ /* we append a single byte to allow for the trailing byte to be appended
+ at the end of this function outside the while() loop */
+ allocsize = (appendlen + stringlen) * 2;
+ newstr = realloc(target, allocsize + 1);
+ if(!newstr) {
+ Curl_safefree(target);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ target = newstr;
+ }
+ memcpy(&target[stringlen], appendthis, appendlen);
+ stringlen += appendlen;
+ }
+ target[stringlen]= '\0';
+ *result = target;
+ return CURLE_OK;
+}
+
diff --git a/src/tool_urlglob.h b/src/tool_urlglob.h
new file mode 100644
index 000000000..9c0813750
--- /dev/null
+++ b/src/tool_urlglob.h
@@ -0,0 +1,75 @@
+#ifndef HEADER_CURL_TOOL_URLGLOB_H
+#define HEADER_CURL_TOOL_URLGLOB_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+typedef enum {
+ UPTSet = 1,
+ UPTCharRange,
+ UPTNumRange
+} URLPatternType;
+
+typedef struct {
+ URLPatternType type;
+ union {
+ struct {
+ char **elements;
+ short size;
+ short ptr_s;
+ } Set;
+ struct {
+ char min_c;
+ char max_c;
+ char ptr_c;
+ int step;
+ } CharRange;
+ struct {
+ int min_n;
+ int max_n;
+ short padlength;
+ int ptr_n;
+ int step;
+ } NumRange ;
+ } content;
+} URLPattern;
+
+/* the total number of globs supported */
+#define GLOB_PATTERN_NUM 9
+
+typedef struct {
+ char *literal[10];
+ URLPattern pattern[GLOB_PATTERN_NUM+1];
+ size_t size;
+ size_t urllen;
+ char *glob_buffer;
+ char beenhere;
+ char errormsg[80]; /* error message buffer */
+} URLGlob;
+
+int glob_url(URLGlob**, char*, int *, FILE *);
+int glob_next_url(char **, URLGlob *);
+int glob_match_url(char **, char*, URLGlob *);
+void glob_cleanup(URLGlob* glob);
+
+#endif /* HEADER_CURL_TOOL_URLGLOB_H */
+
diff --git a/src/tool_util.c b/src/tool_util.c
new file mode 100644
index 000000000..00d205ebc
--- /dev/null
+++ b/src/tool_util.c
@@ -0,0 +1,138 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#include "tool_util.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#if defined(WIN32) && !defined(MSDOS)
+
+struct timeval tool_tvnow(void)
+{
+ /*
+ ** GetTickCount() is available on _all_ Windows versions from W95 up
+ ** to nowadays. Returns milliseconds elapsed since last system boot,
+ ** increases monotonically and wraps once 49.7 days have elapsed.
+ */
+ struct timeval now;
+ DWORD milliseconds = GetTickCount();
+ now.tv_sec = milliseconds / 1000;
+ now.tv_usec = (milliseconds % 1000) * 1000;
+ return now;
+}
+
+#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
+
+struct timeval tool_tvnow(void)
+{
+ /*
+ ** clock_gettime() is granted to be increased monotonically when the
+ ** monotonic clock is queried. Time starting point is unspecified, it
+ ** could be the system start-up time, the Epoch, or something else,
+ ** in any case the time starting point does not change once that the
+ ** system has started up.
+ */
+ struct timeval now;
+ struct timespec tsnow;
+ if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
+ now.tv_sec = tsnow.tv_sec;
+ now.tv_usec = tsnow.tv_nsec / 1000;
+ }
+ /*
+ ** Even when the configure process has truly detected monotonic clock
+ ** availability, it might happen that it is not actually available at
+ ** run-time. When this occurs simply fallback to other time source.
+ */
+#ifdef HAVE_GETTIMEOFDAY
+ else
+ (void)gettimeofday(&now, NULL);
+#else
+ else {
+ now.tv_sec = (long)time(NULL);
+ now.tv_usec = 0;
+ }
+#endif
+ return now;
+}
+
+#elif defined(HAVE_GETTIMEOFDAY)
+
+struct timeval tool_tvnow(void)
+{
+ /*
+ ** gettimeofday() is not granted to be increased monotonically, due to
+ ** clock drifting and external source time synchronization it can jump
+ ** forward or backward in time.
+ */
+ struct timeval now;
+ (void)gettimeofday(&now, NULL);
+ return now;
+}
+
+#else
+
+struct timeval tool_tvnow(void)
+{
+ /*
+ ** time() returns the value of time in seconds since the Epoch.
+ */
+ struct timeval now;
+ now.tv_sec = (long)time(NULL);
+ now.tv_usec = 0;
+ return now;
+}
+
+#endif
+
+/*
+ * Make sure that the first argument is the more recent time, as otherwise
+ * we'll get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
+ */
+long tool_tvdiff(struct timeval newer, struct timeval older)
+{
+ return (newer.tv_sec-older.tv_sec)*1000+
+ (newer.tv_usec-older.tv_usec)/1000;
+}
+
+/*
+ * Same as tool_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double tool_tvdiff_secs(struct timeval newer, struct timeval older)
+{
+ if(newer.tv_sec != older.tv_sec)
+ return (double)(newer.tv_sec-older.tv_sec)+
+ (double)(newer.tv_usec-older.tv_usec)/1000000.0;
+ else
+ return (double)(newer.tv_usec-older.tv_usec)/1000000.0;
+}
+
+/* return the number of seconds in the given input timeval struct */
+long tool_tvlong(struct timeval t1)
+{
+ return t1.tv_sec;
+}
+
diff --git a/src/tool_util.h b/src/tool_util.h
new file mode 100644
index 000000000..d8bb03669
--- /dev/null
+++ b/src/tool_util.h
@@ -0,0 +1,56 @@
+#ifndef HEADER_CURL_TOOL_UTIL_H
+#define HEADER_CURL_TOOL_UTIL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+struct timeval tool_tvnow(void);
+
+/*
+ * Make sure that the first argument (t1) is the more recent time and t2 is
+ * the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
+ */
+long tool_tvdiff(struct timeval t1, struct timeval t2);
+
+/*
+ * Same as tool_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double tool_tvdiff_secs(struct timeval t1, struct timeval t2);
+
+long tool_tvlong(struct timeval t1);
+
+#undef tvnow
+#undef tvdiff
+#undef tvdiff_secs
+#undef tvlong
+
+#define tvnow() tool_tvnow()
+#define tvdiff(a,b) tool_tvdiff((a), (b))
+#define tvdiff_secs(a,b) tool_tvdiff_secs((a), (b))
+#define tvlong(a) tool_tvlong((a))
+
+#endif /* HEADER_CURL_TOOL_UTIL_H */
+
diff --git a/src/tool_version.h b/src/tool_version.h
new file mode 100644
index 000000000..569526bfe
--- /dev/null
+++ b/src/tool_version.h
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_TOOL_VERSION_H
+#define HEADER_CURL_TOOL_VERSION_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include <curl/curlver.h>
+
+#define CURL_NAME "curl"
+#define CURL_COPYRIGHT LIBCURL_COPYRIGHT
+#define CURL_VERSION LIBCURL_VERSION
+#define CURL_VERSION_MAJOR LIBCURL_VERSION_MAJOR
+#define CURL_VERSION_MINOR LIBCURL_VERSION_MINOR
+#define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH
+#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "
+
+#endif /* HEADER_CURL_TOOL_VERSION_H */
diff --git a/src/tool_vms.c b/src/tool_vms.c
new file mode 100644
index 000000000..4a6a6f58e
--- /dev/null
+++ b/src/tool_vms.c
@@ -0,0 +1,219 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef __VMS
+
+#if defined(__DECC) && !defined(__VAX) && \
+ defined(__CRTL_VER) && (__CRTL_VER >= 70301000)
+#include <unixlib.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+#include "curlx.h"
+
+#include "curlmsg_vms.h"
+#include "tool_vms.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+void decc$__posix_exit(int __status);
+void decc$exit(int __status);
+
+static int vms_shell = -1;
+
+/* VMS has a DCL shell and and also has Unix shells ported to it.
+ * When curl is running under a Unix shell, we want it to be as much
+ * like Unix as possible.
+ */
+int is_vms_shell(void)
+{
+ char *shell;
+
+ /* Have we checked the shell yet? */
+ if(vms_shell >= 0)
+ return vms_shell;
+
+ shell = getenv("SHELL");
+
+ /* No shell, means DCL */
+ if(shell == NULL) {
+ vms_shell = 1;
+ return 1;
+ }
+
+ /* Have to make sure some one did not set shell to DCL */
+ if(strcmp(shell, "DCL") == 0) {
+ vms_shell = 1;
+ return 1;
+ }
+
+ vms_shell = 0;
+ return 0;
+}
+
+/*
+ * VMS has two exit() routines. When running under a Unix style shell, then
+ * Unix style and the __posix_exit() routine is used.
+ *
+ * When running under the DCL shell, then the VMS encoded codes and decc$exit()
+ * is used.
+ *
+ * We can not use exit() or return a code from main() because the actual
+ * routine called depends on both the compiler version, compile options, and
+ * feature macro settings, and one of the exit routines is hidden at compile
+ * time.
+ *
+ * Since we want Curl to work properly under the VMS DCL shell and Unix
+ * shells under VMS, this routine should compile correctly regardless of
+ * the settings.
+ */
+
+void vms_special_exit(int code, int vms_show)
+{
+ int vms_code;
+
+ /* The Posix exit mode is only available after VMS 7.0 */
+#if __CRTL_VER >= 70000000
+ if(is_vms_shell() == 0) {
+ decc$__posix_exit(code);
+ }
+#endif
+
+ if(code > CURL_LAST) { /* If CURL_LAST exceeded then */
+ vms_code = CURL_LAST; /* curlmsg.h is out of sync. */
+ }
+ else {
+ vms_code = vms_cond[code] | vms_show;
+ }
+ decc$exit(vms_code);
+}
+
+#if defined(__DECC) && !defined(__VAX) && \
+ defined(__CRTL_VER) && (__CRTL_VER >= 70301000)
+
+/*
+ * 2004-09-19 SMS.
+ *
+ * decc_init()
+ *
+ * On non-VAX systems, use LIB$INITIALIZE to set a collection of C
+ * RTL features without using the DECC$* logical name method, nor
+ * requiring the user to define the corresponding logical names.
+ */
+
+/* Structure to hold a DECC$* feature name and its desired value. */
+typedef struct {
+ char *name;
+ int value;
+} decc_feat_t;
+
+/* Array of DECC$* feature names and their desired values. */
+static decc_feat_t decc_feat_array[] = {
+ /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
+ { "DECC$ARGV_PARSE_STYLE", 1 },
+ /* Preserve case for file names on ODS5 disks. */
+ { "DECC$EFS_CASE_PRESERVE", 1 },
+ /* Enable multiple dots (and most characters) in ODS5 file names,
+ while preserving VMS-ness of ";version". */
+ { "DECC$EFS_CHARSET", 1 },
+ /* List terminator. */
+ { (char *)NULL, 0 }
+};
+
+/* Flag to sense if decc_init() was called. */
+static int decc_init_done = -1;
+
+/* LIB$INITIALIZE initialization function. */
+static void decc_init(void)
+{
+ int feat_index;
+ int feat_value;
+ int feat_value_max;
+ int feat_value_min;
+ int i;
+ int sts;
+
+ /* Set the global flag to indicate that LIB$INITIALIZE worked. */
+ decc_init_done = 1;
+
+ /* Loop through all items in the decc_feat_array[]. */
+ for(i = 0; decc_feat_array[i].name != NULL; i++) {
+
+ /* Get the feature index. */
+ feat_index = decc$feature_get_index( decc_feat_array[i].name);
+
+ if(feat_index >= 0) {
+ /* Valid item. Collect its properties. */
+ feat_value = decc$feature_get_value( feat_index, 1);
+ feat_value_min = decc$feature_get_value( feat_index, 2);
+ feat_value_max = decc$feature_get_value( feat_index, 3);
+
+ if((decc_feat_array[i].value >= feat_value_min) &&
+ (decc_feat_array[i].value <= feat_value_max)) {
+ /* Valid value. Set it if necessary. */
+ if(feat_value != decc_feat_array[i].value) {
+ sts = decc$feature_set_value( feat_index, 1,
+ decc_feat_array[i].value);
+ }
+ }
+ else {
+ /* Invalid DECC feature value. */
+ printf(" INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n",
+ feat_value,
+ feat_value_min, decc_feat_array[i].name, feat_value_max);
+ }
+ }
+ else {
+ /* Invalid DECC feature name. */
+ printf(" UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[i].name);
+ }
+
+ }
+}
+
+/* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */
+
+#pragma nostandard
+
+/* Establish the LIB$INITIALIZE PSECTs, with proper alignment and
+ other attributes. Note that "nopic" is significant only on VAX. */
+#pragma extern_model save
+#pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt
+const int spare[8] = {0};
+#pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt
+void (*const x_decc_init)() = decc_init;
+#pragma extern_model restore
+
+/* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */
+#pragma extern_model save
+int LIB$INITIALIZE(void);
+#pragma extern_model strict_refdef
+int dmy_lib$initialize = (int) LIB$INITIALIZE;
+#pragma extern_model restore
+
+#pragma standard
+
+#endif /* __DECC && !__VAX && __CRTL_VER && __CRTL_VER >= 70301000 */
+
+#endif /* __VMS */
+
diff --git a/src/tool_vms.h b/src/tool_vms.h
new file mode 100644
index 000000000..5bb262e2e
--- /dev/null
+++ b/src/tool_vms.h
@@ -0,0 +1,40 @@
+#ifndef HEADER_CURL_TOOL_VMS_H
+#define HEADER_CURL_TOOL_VMS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef __VMS
+
+int is_vms_shell(void);
+void vms_special_exit(int code, int vms_show);
+
+#undef exit
+#define exit(__code) vms_special_exit((__code), (0))
+
+#define VMS_STS(c,f,e,s) (((c&0xF)<<28)|((f&0xFFF)<<16)|((e&0x1FFF)<3)|(s&7))
+#define VMSSTS_HIDE VMS_STS(1,0,0,0)
+
+#endif /* __VMS */
+
+#endif /* HEADER_CURL_TOOL_VMS_H */
+
diff --git a/src/tool_writeenv.c b/src/tool_writeenv.c
new file mode 100644
index 000000000..a9462d004
--- /dev/null
+++ b/src/tool_writeenv.c
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef USE_ENVIRONMENT
+
+#ifdef __riscos__
+# include <kernel.h>
+#endif
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "tool_writeenv.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+static const struct
+{
+ const char * name;
+ CURLINFO id;
+ enum {
+ writeenv_NONE,
+ writeenv_DOUBLE,
+ writeenv_LONG,
+ writeenv_STRING
+ } type;
+} variables[14] =
+{
+ {"curl_url_effective", CURLINFO_EFFECTIVE_URL, writeenv_STRING},
+ {"curl_http_code", CURLINFO_RESPONSE_CODE, writeenv_LONG},
+ {"curl_time_total", CURLINFO_TOTAL_TIME, writeenv_DOUBLE},
+ {"curl_time_namelookup", CURLINFO_NAMELOOKUP_TIME, writeenv_DOUBLE},
+ {"curl_time_connect", CURLINFO_CONNECT_TIME, writeenv_DOUBLE},
+ {"curl_time_pretransfer", CURLINFO_PRETRANSFER_TIME, writeenv_DOUBLE},
+ {"curl_time_starttransfer", CURLINFO_STARTTRANSFER_TIME, writeenv_DOUBLE},
+ {"curl_size_header", CURLINFO_HEADER_SIZE, writeenv_LONG},
+ {"curl_size_request", CURLINFO_REQUEST_SIZE, writeenv_LONG},
+ {"curl_size_download", CURLINFO_SIZE_DOWNLOAD, writeenv_DOUBLE},
+ {"curl_size_upload", CURLINFO_SIZE_UPLOAD, writeenv_DOUBLE},
+ {"curl_speed_download", CURLINFO_SPEED_DOWNLOAD, writeenv_DOUBLE},
+ {"curl_speed_upload", CURLINFO_SPEED_UPLOAD, writeenv_DOUBLE},
+ {NULL, 0, writeenv_NONE}
+ };
+
+static void internalSetEnv(const char * name, char * value)
+{
+ /* Add your OS-specific code here. */
+#ifdef __riscos__
+ _kernel_setenv(name, value);
+#elif defined (CURLDEBUG)
+ curl_memlog("ENV %s = %s\n", name, value);
+#endif
+ return;
+}
+
+void ourWriteEnv(CURL *curl)
+{
+ unsigned int i;
+ char *string, numtext[10];
+ long longinfo;
+ double doubleinfo;
+
+ for(i=0; variables[i].name; i++) {
+ switch (variables[i].type) {
+ case writeenv_STRING:
+ if(curl_easy_getinfo(curl, variables[i].id, &string) == CURLE_OK)
+ internalSetEnv(variables[i].name, string);
+ else
+ internalSetEnv(variables[i].name, NULL);
+ break;
+
+ case writeenv_LONG:
+ if(curl_easy_getinfo(curl, variables[i].id, &longinfo) == CURLE_OK) {
+ curl_msprintf(numtext, "%5ld", longinfo);
+ internalSetEnv(variables[i].name, numtext);
+ }
+ else
+ internalSetEnv(variables[i].name, NULL);
+ break;
+ case writeenv_DOUBLE:
+ if(curl_easy_getinfo(curl, variables[i].id, &doubleinfo) == CURLE_OK) {
+ curl_msprintf(numtext, "%6.2f", doubleinfo);
+ internalSetEnv(variables[i].name, numtext);
+ }
+ else
+ internalSetEnv(variables[i].name, NULL);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return;
+}
+
+#endif
diff --git a/src/tool_writeenv.h b/src/tool_writeenv.h
new file mode 100644
index 000000000..c0a952fe0
--- /dev/null
+++ b/src/tool_writeenv.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_TOOL_WRITEENV_H
+#define HEADER_CURL_TOOL_WRITEENV_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef USE_ENVIRONMENT
+
+void ourWriteEnv(CURL *curl);
+
+#else
+# define ourWriteEnv(x) Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_TOOL_WRITEENV_H */
+
diff --git a/src/tool_writeout.c b/src/tool_writeout.c
new file mode 100644
index 000000000..6038a210a
--- /dev/null
+++ b/src/tool_writeout.c
@@ -0,0 +1,295 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
+#include <curl/mprintf.h>
+
+#include "tool_cfgable.h"
+#include "tool_writeout.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+typedef enum {
+ VAR_NONE, /* must be the first */
+ VAR_TOTAL_TIME,
+ VAR_NAMELOOKUP_TIME,
+ VAR_CONNECT_TIME,
+ VAR_APPCONNECT_TIME,
+ VAR_PRETRANSFER_TIME,
+ VAR_STARTTRANSFER_TIME,
+ VAR_SIZE_DOWNLOAD,
+ VAR_SIZE_UPLOAD,
+ VAR_SPEED_DOWNLOAD,
+ VAR_SPEED_UPLOAD,
+ VAR_HTTP_CODE,
+ VAR_HTTP_CODE_PROXY,
+ VAR_HEADER_SIZE,
+ VAR_REQUEST_SIZE,
+ VAR_EFFECTIVE_URL,
+ VAR_CONTENT_TYPE,
+ VAR_NUM_CONNECTS,
+ VAR_REDIRECT_TIME,
+ VAR_REDIRECT_COUNT,
+ VAR_FTP_ENTRY_PATH,
+ VAR_REDIRECT_URL,
+ VAR_SSL_VERIFY_RESULT,
+ VAR_EFFECTIVE_FILENAME,
+ VAR_NUM_OF_VARS /* must be the last */
+} replaceid;
+
+struct variable {
+ const char *name;
+ replaceid id;
+};
+
+
+static const struct variable replacements[]={
+ {"url_effective", VAR_EFFECTIVE_URL},
+ {"http_code", VAR_HTTP_CODE},
+ {"response_code", VAR_HTTP_CODE},
+ {"http_connect", VAR_HTTP_CODE_PROXY},
+ {"time_total", VAR_TOTAL_TIME},
+ {"time_namelookup", VAR_NAMELOOKUP_TIME},
+ {"time_connect", VAR_CONNECT_TIME},
+ {"time_appconnect", VAR_APPCONNECT_TIME},
+ {"time_pretransfer", VAR_PRETRANSFER_TIME},
+ {"time_starttransfer", VAR_STARTTRANSFER_TIME},
+ {"size_header", VAR_HEADER_SIZE},
+ {"size_request", VAR_REQUEST_SIZE},
+ {"size_download", VAR_SIZE_DOWNLOAD},
+ {"size_upload", VAR_SIZE_UPLOAD},
+ {"speed_download", VAR_SPEED_DOWNLOAD},
+ {"speed_upload", VAR_SPEED_UPLOAD},
+ {"content_type", VAR_CONTENT_TYPE},
+ {"num_connects", VAR_NUM_CONNECTS},
+ {"time_redirect", VAR_REDIRECT_TIME},
+ {"num_redirects", VAR_REDIRECT_COUNT},
+ {"ftp_entry_path", VAR_FTP_ENTRY_PATH},
+ {"redirect_url", VAR_REDIRECT_URL},
+ {"ssl_verify_result", VAR_SSL_VERIFY_RESULT},
+ {"filename_effective", VAR_EFFECTIVE_FILENAME},
+ {NULL, VAR_NONE}
+};
+
+void ourWriteOut(CURL *curl, struct OutStruct *outs, const char *writeinfo)
+{
+ FILE *stream = stdout;
+ const char *ptr = writeinfo;
+ char *stringp;
+ long longinfo;
+ double doubleinfo;
+
+ while(ptr && *ptr) {
+ if('%' == *ptr) {
+ if('%' == ptr[1]) {
+ /* an escaped %-letter */
+ fputc('%', stream);
+ ptr += 2;
+ }
+ else {
+ /* this is meant as a variable to output */
+ char *end;
+ char keepit;
+ int i;
+ if(('{' == ptr[1]) && ((end = strchr(ptr, '}')) != NULL)) {
+ bool match = FALSE;
+ ptr += 2; /* pass the % and the { */
+ keepit = *end;
+ *end = 0; /* zero terminate */
+ for(i = 0; replacements[i].name; i++) {
+ if(curl_strequal(ptr, replacements[i].name)) {
+ match = TRUE;
+ switch(replacements[i].id) {
+ case VAR_EFFECTIVE_URL:
+ if((CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &stringp))
+ && stringp)
+ fputs(stringp, stream);
+ break;
+ case VAR_HTTP_CODE:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &longinfo))
+ fprintf(stream, "%03ld", longinfo);
+ break;
+ case VAR_HTTP_CODE_PROXY:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_HTTP_CONNECTCODE,
+ &longinfo))
+ fprintf(stream, "%03ld", longinfo);
+ break;
+ case VAR_HEADER_SIZE:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_HEADER_SIZE, &longinfo))
+ fprintf(stream, "%ld", longinfo);
+ break;
+ case VAR_REQUEST_SIZE:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_REQUEST_SIZE, &longinfo))
+ fprintf(stream, "%ld", longinfo);
+ break;
+ case VAR_NUM_CONNECTS:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_NUM_CONNECTS, &longinfo))
+ fprintf(stream, "%ld", longinfo);
+ break;
+ case VAR_REDIRECT_COUNT:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &longinfo))
+ fprintf(stream, "%ld", longinfo);
+ break;
+ case VAR_REDIRECT_TIME:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME,
+ &doubleinfo))
+ fprintf(stream, "%.3f", doubleinfo);
+ break;
+ case VAR_TOTAL_TIME:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &doubleinfo))
+ fprintf(stream, "%.3f", doubleinfo);
+ break;
+ case VAR_NAMELOOKUP_TIME:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME,
+ &doubleinfo))
+ fprintf(stream, "%.3f", doubleinfo);
+ break;
+ case VAR_CONNECT_TIME:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &doubleinfo))
+ fprintf(stream, "%.3f", doubleinfo);
+ break;
+ case VAR_APPCONNECT_TIME:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME,
+ &doubleinfo))
+ fprintf(stream, "%.3f", doubleinfo);
+ break;
+ case VAR_PRETRANSFER_TIME:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME,
+ &doubleinfo))
+ fprintf(stream, "%.3f", doubleinfo);
+ break;
+ case VAR_STARTTRANSFER_TIME:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME,
+ &doubleinfo))
+ fprintf(stream, "%.3f", doubleinfo);
+ break;
+ case VAR_SIZE_UPLOAD:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &doubleinfo))
+ fprintf(stream, "%.0f", doubleinfo);
+ break;
+ case VAR_SIZE_DOWNLOAD:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD,
+ &doubleinfo))
+ fprintf(stream, "%.0f", doubleinfo);
+ break;
+ case VAR_SPEED_DOWNLOAD:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD,
+ &doubleinfo))
+ fprintf(stream, "%.3f", doubleinfo);
+ break;
+ case VAR_SPEED_UPLOAD:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &doubleinfo))
+ fprintf(stream, "%.3f", doubleinfo);
+ break;
+ case VAR_CONTENT_TYPE:
+ if((CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &stringp))
+ && stringp)
+ fputs(stringp, stream);
+ break;
+ case VAR_FTP_ENTRY_PATH:
+ if((CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_FTP_ENTRY_PATH, &stringp))
+ && stringp)
+ fputs(stringp, stream);
+ break;
+ case VAR_REDIRECT_URL:
+ if((CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_REDIRECT_URL, &stringp))
+ && stringp)
+ fputs(stringp, stream);
+ break;
+ case VAR_SSL_VERIFY_RESULT:
+ if(CURLE_OK ==
+ curl_easy_getinfo(curl, CURLINFO_SSL_VERIFYRESULT,
+ &longinfo))
+ fprintf(stream, "%ld", longinfo);
+ break;
+ case VAR_EFFECTIVE_FILENAME:
+ if(outs->filename)
+ fprintf(stream, "%s", outs->filename);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ if(!match) {
+ fprintf(stderr, "curl: unknown --write-out variable: '%s'\n", ptr);
+ }
+ ptr = end + 1; /* pass the end */
+ *end = keepit;
+ }
+ else {
+ /* illegal syntax, then just output the characters that are used */
+ fputc('%', stream);
+ fputc(ptr[1], stream);
+ ptr += 2;
+ }
+ }
+ }
+ else if('\\' == *ptr) {
+ switch(ptr[1]) {
+ case 'r':
+ fputc('\r', stream);
+ break;
+ case 'n':
+ fputc('\n', stream);
+ break;
+ case 't':
+ fputc('\t', stream);
+ break;
+ default:
+ /* unknown, just output this */
+ fputc(*ptr, stream);
+ fputc(ptr[1], stream);
+ break;
+ }
+ ptr += 2;
+ }
+ else {
+ fputc(*ptr, stream);
+ ptr++;
+ }
+ }
+
+}
diff --git a/src/tool_writeout.h b/src/tool_writeout.h
new file mode 100644
index 000000000..4dd3a75a5
--- /dev/null
+++ b/src/tool_writeout.h
@@ -0,0 +1,28 @@
+#ifndef HEADER_CURL_TOOL_WRITEOUT_H
+#define HEADER_CURL_TOOL_WRITEOUT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+void ourWriteOut(CURL *curl, struct OutStruct *outs, const char *writeinfo);
+
+#endif /* HEADER_CURL_TOOL_WRITEOUT_H */
diff --git a/src/tool_xattr.c b/src/tool_xattr.c
new file mode 100644
index 000000000..505bdb17a
--- /dev/null
+++ b/src/tool_xattr.c
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef HAVE_FSETXATTR
+# include <sys/xattr.h> /* header from libc, not from libattr */
+#endif
+
+#include "tool_xattr.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+#ifdef HAVE_FSETXATTR
+
+/* mapping table of curl metadata to extended attribute names */
+static const struct xattr_mapping {
+ const char *attr; /* name of the xattr */
+ CURLINFO info;
+} mappings[] = {
+ /* mappings proposed by
+ * http://freedesktop.org/wiki/CommonExtendedAttributes
+ */
+ { "user.xdg.origin.url", CURLINFO_EFFECTIVE_URL },
+ { "user.mime_type", CURLINFO_CONTENT_TYPE },
+ { NULL, CURLINFO_NONE } /* last element, abort loop here */
+};
+
+/* store metadata from the curl request alongside the downloaded
+ * file using extended attributes
+ */
+int fwrite_xattr(CURL *curl, int fd)
+{
+ int i = 0;
+ int err = 0;
+ /* loop through all xattr-curlinfo pairs and abort on a set error */
+ while(err == 0 && mappings[i].attr != NULL) {
+ char *value = NULL;
+ CURLcode rc = curl_easy_getinfo(curl, mappings[i].info, &value);
+ if(rc == CURLE_OK && value) {
+#ifdef HAVE_FSETXATTR_6
+ err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0, 0);
+#elif defined(HAVE_FSETXATTR_5)
+ err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0);
+#endif
+ }
+ i++;
+ }
+ return err;
+}
+#else
+int fwrite_xattr(CURL *curl, int fd)
+{
+ (void)curl;
+ (void)fd;
+ return 0;
+}
+#endif
diff --git a/src/tool_xattr.h b/src/tool_xattr.h
new file mode 100644
index 000000000..3f8f585e4
--- /dev/null
+++ b/src/tool_xattr.h
@@ -0,0 +1,28 @@
+#ifndef HEADER_CURL_TOOL_XATTR_H
+#define HEADER_CURL_TOOL_XATTR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+int fwrite_xattr(CURL *curl, int fd);
+
+#endif /* HEADER_CURL_TOOL_XATTR_H */
diff --git a/src/vc6curlsrc.dsp b/src/vc6curlsrc.dsp
new file mode 100644
index 000000000..7c757654d
--- /dev/null
+++ b/src/vc6curlsrc.dsp
@@ -0,0 +1,498 @@
+# Microsoft Developer Studio Project File - Name="curlsrc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=curlsrc - Win32 using libcurl LIB Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "curlsrc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "curlsrc.mak" CFG="curlsrc - Win32 using libcurl LIB Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "curlsrc - Win32 using libcurl DLL Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "curlsrc - Win32 using libcurl DLL Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "curlsrc - Win32 using libcurl LIB Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "curlsrc - Win32 using libcurl LIB Release" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "curlsrc - Win32 using libcurl DLL Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "DLL-Debug"
+# PROP BASE Intermediate_Dir "DLL-Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DLL-Debug"
+# PROP Intermediate_Dir "DLL-Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\lib" /I "..\include" /I "." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_CONSOLE" /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\lib" /I "..\include" /I "." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_CONSOLE" /FD /GZ /c
+# ADD BASE RSC /l 0x409 /i "..\include" /d "_DEBUG"
+# ADD RSC /l 0x409 /i "..\include" /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 libcurld_imp.lib kernel32.lib ws2_32.lib wldap32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"DLL-Debug/curl.exe" /pdbtype:sept /libpath:"..\lib\DLL-Debug"
+# ADD LINK32 libcurld_imp.lib kernel32.lib ws2_32.lib wldap32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"DLL-Debug/curl.exe" /pdbtype:sept /libpath:"..\lib\DLL-Debug"
+
+!ELSEIF "$(CFG)" == "curlsrc - Win32 using libcurl DLL Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "DLL-Release"
+# PROP BASE Intermediate_Dir "DLL-Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "DLL-Release"
+# PROP Intermediate_Dir "DLL-Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "..\lib" /I "..\include" /I "." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_CONSOLE" /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\lib" /I "..\include" /I "." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_CONSOLE" /FD /c
+# ADD BASE RSC /l 0x409 /i "..\include" /d "NDEBUG"
+# ADD RSC /l 0x409 /i "..\include" /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 libcurl_imp.lib kernel32.lib ws2_32.lib wldap32.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"DLL-Release/curl.exe" /libpath:"..\lib\DLL-Release"
+# ADD LINK32 libcurl_imp.lib kernel32.lib ws2_32.lib wldap32.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"DLL-Release/curl.exe" /libpath:"..\lib\DLL-Release"
+
+!ELSEIF "$(CFG)" == "curlsrc - Win32 using libcurl LIB Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "LIB-Debug"
+# PROP BASE Intermediate_Dir "LIB-Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "LIB-Debug"
+# PROP Intermediate_Dir "LIB-Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\lib" /I "..\include" /I "." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_CONSOLE" /D "CURL_STATICLIB" /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\lib" /I "..\include" /I "." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_CONSOLE" /D "CURL_STATICLIB" /FD /GZ /c
+# ADD BASE RSC /l 0x409 /i "..\include" /d "_DEBUG"
+# ADD RSC /l 0x409 /i "..\include" /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 libcurld.lib kernel32.lib ws2_32.lib wldap32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"LIB-Debug/curl.exe" /pdbtype:sept /libpath:"..\lib\LIB-Debug"
+# ADD LINK32 libcurld.lib kernel32.lib ws2_32.lib wldap32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"LIB-Debug/curl.exe" /pdbtype:sept /libpath:"..\lib\LIB-Debug"
+
+!ELSEIF "$(CFG)" == "curlsrc - Win32 using libcurl LIB Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "LIB-Release"
+# PROP BASE Intermediate_Dir "LIB-Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "LIB-Release"
+# PROP Intermediate_Dir "LIB-Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "..\lib" /I "..\include" /I "." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_CONSOLE" /D "CURL_STATICLIB" /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\lib" /I "..\include" /I "." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_CONSOLE" /D "CURL_STATICLIB" /FD /c
+# ADD BASE RSC /l 0x409 /i "..\include" /d "NDEBUG"
+# ADD RSC /l 0x409 /i "..\include" /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 libcurl.lib kernel32.lib ws2_32.lib wldap32.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"LIB-Release/curl.exe" /libpath:"..\lib\LIB-Release"
+# ADD LINK32 libcurl.lib kernel32.lib ws2_32.lib wldap32.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"LIB-Release/curl.exe" /libpath:"..\lib\LIB-Release"
+
+!ENDIF
+
+# Begin Target
+
+# Name "curlsrc - Win32 using libcurl DLL Debug"
+# Name "curlsrc - Win32 using libcurl DLL Release"
+# Name "curlsrc - Win32 using libcurl LIB Debug"
+# Name "curlsrc - Win32 using libcurl LIB Release"
+# Begin Group "Source Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\hugehelp.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib\nonblock.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib\rawstr.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib\strtoofft.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_binmode.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_bname.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_dbg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_hdr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_prg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_rea.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_see.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_wrt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cfgable.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_convert.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_dirhie.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_doswin.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_easysrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_formparse.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getparam.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getpass.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_help.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_helpers.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_homedir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_libinfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_main.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_metalink.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_mfiles.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_msgs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operhlp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_panykey.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_paramhlp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_parsecfg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_setopt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_sleep.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_urlglob.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_vms.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_writeenv.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_writeout.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_xattr.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=".\config-win32.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\hugehelp.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib\nonblock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib\rawstr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\lib\strtoofft.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_binmode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_bname.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_dbg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_hdr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_prg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_rea.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_see.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_wrt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cfgable.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_convert.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_dirhie.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_doswin.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_easysrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_formparse.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getparam.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getpass.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_help.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_helpers.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_homedir.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_libinfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_main.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_metalink.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_mfiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_msgs.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operhlp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_panykey.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_paramhlp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_parsecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_sdecls.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_setopt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_setup.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_sleep.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_urlglob.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_util.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_version.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_vms.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_writeenv.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_writeout.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_xattr.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\curl.rc
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/src/vc6curlsrc.dsw b/src/vc6curlsrc.dsw
new file mode 100644
index 000000000..6b2db6fba
--- /dev/null
+++ b/src/vc6curlsrc.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "curlsrc"=".\vc6curlsrc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+