Implementation notes:
- This is a true OS/400 implementation, not a PASE implementation (for PASE,
-use AIX implementation).
+ This is a true OS/400 ILE implementation, not a PASE implementation (for
+PASE, use AIX implementation).
The biggest problem with OS/400 is EBCDIC. Libcurl implements an internal
conversion mechanism, but it has been designed for computers that have a
CURLOPT_PASSWORD
CURLOPT_PINNEDPUBLICKEY
CURLOPT_PRE_PROXY
+ CURLOPT_PROTOCOLS_STR
CURLOPT_PROXY
CURLOPT_PROXYPASSWORD
CURLOPT_PROXYUSERNAME
CURLOPT_PROXY_TLSAUTH_USERNAME
CURLOPT_RANDOM_FILE
CURLOPT_RANGE
+ CURLOPT_REDIR_PROTOCOLS_STR
CURLOPT_REFERER
CURLOPT_REQUEST_TARGET
CURLOPT_RTSP_SESSION_UID
CURLOPT_SERVICE_NAME
CURLOPT_SOCKS5_GSSAPI_SERVICE
CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
+ CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256
CURLOPT_SSH_KNOWNHOSTS
CURLOPT_SSH_PRIVATE_KEYFILE
CURLOPT_SSH_PUBLIC_KEYFILE
CURLOPT_USERNAME
CURLOPT_USERPWD
CURLOPT_XOAUTH2_BEARER
- Else it is the same as for curl_easy_setopt().
+ All blob options are also supported.
+ In all other cases, it ignores the ccsid parameter and behaves as
+curl_easy_setopt().
Note that CURLOPT_ERRORBUFFER is not in the list above, since it gives the
address of an (empty) character buffer, not the address of a string.
-CURLOPT_POSTFIELDS stores the address of static binary data (of type void *) and
-thus is not converted. If CURLOPT_COPYPOSTFIELDS is issued after
+CURLOPT_POSTFIELDS stores the address of static binary data (of type void *)
+and thus is not converted. If CURLOPT_COPYPOSTFIELDS is issued after
CURLOPT_POSTFIELDSIZE != -1, the data size is adjusted according to the
CCSID conversion result length.
after use.
Other options are processed like in curl_easy_getinfo().
+_ curl_easy_strerror_ccsid(), curl_multi_strerror_ccsid(),
+curl_share_strerror_ccsid() and curl_url_strerror_ccsid() work as their
+non-ccsid version and return a string encoded in the additional ccsid
+parameter. These strings belong to libcurl and may not be freed by the caller.
+A subsequent call to the same procedure in the same thread invalidates the
+previous result.
+
_ curl_pushheader_bynum_cssid() and curl_pushheader_byname_ccsid()
Although the prototypes are self-explanatory, the returned string pointer
should be released with curl_free() after use, as opposite to the non-ccsid
supported ccsid. However the caller should release the returned pointer with
curl_free() after use.
+_ curl_easy_header_ccsid() works as its non-CCSID counterpart but requires an
+additional ccsid parameter specifying the name parameter encoding. The output
+hout parameter is kept in libcurl's encoding and should not be altered.
+
+_ curl_from_ccsid() and curl_to_ccsid() are string encoding conversion
+functions between ASCII (latin1) and the given CCSID. The first parameter is
+the source string, the second is the CCSID and the returned value is a pointer
+to the dynamically allocated string. These functions do not impact on Curl's
+behavior and are only provided for user convenience. After use, returned values
+must be released with curl_free().
+
Standard compilation environment does support neither autotools nor make;
in fact, very few common utilities are available. As a consequence, the
cp initscript.sh makelog): this is intended to create the makelog file with
an ASCII CCSID!
_ Enter the command "sh makefile.sh > makelog 2>&1"
-_ Examine the makelog file to check for compilation errors.
+_ Examine the makelog file to check for compilation errors. CZM0383 warnings on
+ C or system standard API come from QADRT inlining and can safely be ignored.
Leaving file initscript.sh unchanged, this will produce the following OS/400
objects:
ILE/RPG support:
- Since 95% of the OS/400 programmers use ILE/RPG exclusively, a definition
- /INCLUDE member is provided for this language. To include all libcurl
- definitions in an ILE/RPG module, line
+ Since most of the ILE OS/400 programmers use ILE/RPG exclusively, a
+definition /INCLUDE member is provided for this language. To include all
+libcurl definitions in an ILE/RPG module, line
h bnddir('CURL/CURL')
}
-char *curl_version_ccsid(unsigned int ccsid)
+static char *
+keyed_string(localkey_t key, const char *ascii, unsigned int ccsid)
{
int i;
- char *aversion;
- char *eversion;
+ char *ebcdic;
- aversion = curl_version();
+ if(!ascii)
+ return (char *) NULL;
- if(!aversion)
- return aversion;
+ i = MAX_CONV_EXPANSION * (strlen(ascii) + 1);
- i = strlen(aversion) + 1;
- i *= MAX_CONV_EXPANSION;
+ ebcdic = Curl_thread_buffer(key, i);
+ if(!ebcdic)
+ return ebcdic;
- eversion = Curl_thread_buffer(LK_CURL_VERSION, i);
- if(!eversion)
+ if(convert(ebcdic, i, ccsid, ascii, -1, ASCII_CCSID) < 0)
return (char *) NULL;
- if(convert(eversion, i, ccsid, aversion, -1, ASCII_CCSID) < 0)
- return (char *) NULL;
+ return ebcdic;
+}
+
+
+const char *
+curl_to_ccsid(const char *s, unsigned int ccsid)
+{
+ if(s)
+ s = dynconvert(ccsid, s, -1, ASCII_CCSID);
+ return s;
+}
- return eversion;
+
+const char *
+curl_from_ccsid(const char *s, unsigned int ccsid)
+{
+ if(s)
+ s = dynconvert(ASCII_CCSID, s, -1, ccsid);
+ return s;
+}
+
+
+char *
+curl_version_ccsid(unsigned int ccsid)
+{
+ return keyed_string(LK_CURL_VERSION, curl_version(), ccsid);
}
offsetof(curl_version_info_data, capath),
offsetof(curl_version_info_data, zstd_version),
offsetof(curl_version_info_data, hyper_version),
- offsetof(curl_version_info_data, gsasl_version)
+ offsetof(curl_version_info_data, gsasl_version),
+ offsetof(curl_version_info_data, feature_names)
};
/* The assertion below is possible, because although the second operand
is an enum member, the first is a #define. In that case, the OS/400 C
compiler seems to compare string values after substitution. */
-#if CURLVERSION_NOW != CURLVERSION_TENTH
+#if CURLVERSION_NOW != CURLVERSION_ELEVENTH
#error curl_version_info_data structure has changed: upgrade this procedure.
#endif
- /* If caller has been compiled with a new version, error. */
+ /* If caller has been compiled with a newer version, error. */
if(stamp > CURLVERSION_NOW)
return (curl_version_info_data *) NULL;
const char *
curl_easy_strerror_ccsid(CURLcode error, unsigned int ccsid)
{
- int i;
- const char *s;
- char *buf;
-
- s = curl_easy_strerror(error);
-
- if(!s)
- return s;
-
- i = MAX_CONV_EXPANSION * (strlen(s) + 1);
-
- buf = Curl_thread_buffer(LK_EASY_STRERROR, i);
- if(!buf)
- return (const char *) NULL;
-
- if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
- return (const char *) NULL;
-
- return (const char *) buf;
+ return keyed_string(LK_EASY_STRERROR, curl_easy_strerror(error), ccsid);
}
const char *
curl_share_strerror_ccsid(CURLSHcode error, unsigned int ccsid)
{
- int i;
- const char *s;
- char *buf;
-
- s = curl_share_strerror(error);
-
- if(!s)
- return s;
-
- i = MAX_CONV_EXPANSION * (strlen(s) + 1);
-
- buf = Curl_thread_buffer(LK_SHARE_STRERROR, i);
- if(!buf)
- return (const char *) NULL;
-
- if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
- return (const char *) NULL;
-
- return (const char *) buf;
+ return keyed_string(LK_SHARE_STRERROR, curl_share_strerror(error), ccsid);
}
const char *
curl_multi_strerror_ccsid(CURLMcode error, unsigned int ccsid)
{
- int i;
- const char *s;
- char *buf;
-
- s = curl_multi_strerror(error);
-
- if(!s)
- return s;
-
- i = MAX_CONV_EXPANSION * (strlen(s) + 1);
-
- buf = Curl_thread_buffer(LK_MULTI_STRERROR, i);
- if(!buf)
- return (const char *) NULL;
+ return keyed_string(LK_MULTI_STRERROR, curl_multi_strerror(error), ccsid);
+}
- if(convert(buf, i, ccsid, s, -1, ASCII_CCSID) < 0)
- return (const char *) NULL;
- return (const char *) buf;
+const char *
+curl_url_strerror_ccsid(CURLUcode error, unsigned int ccsid)
+{
+ return keyed_string(LK_URL_STRERROR, curl_url_strerror(error), ccsid);
}
CURLcode
-curl_easy_setopt_ccsid(CURL *curl, CURLoption tag, ...)
+curl_easy_setopt_ccsid(CURL *easy, CURLoption tag, ...)
{
CURLcode result;
va_list arg;
- struct Curl_easy *data;
char *s;
- char *cp;
+ char *cp = NULL;
unsigned int ccsid;
curl_off_t pfsize;
- data = (struct Curl_easy *) curl;
va_start(arg, tag);
switch(tag) {
case CURLOPT_PASSWORD:
case CURLOPT_PINNEDPUBLICKEY:
case CURLOPT_PRE_PROXY:
+ case CURLOPT_PROTOCOLS_STR:
case CURLOPT_PROXY:
case CURLOPT_PROXYPASSWORD:
case CURLOPT_PROXYUSERNAME:
case CURLOPT_PROXY_TLSAUTH_USERNAME:
case CURLOPT_RANDOM_FILE:
case CURLOPT_RANGE:
+ case CURLOPT_REDIR_PROTOCOLS_STR:
case CURLOPT_REFERER:
case CURLOPT_REQUEST_TARGET:
case CURLOPT_RTSP_SESSION_ID:
case CURLOPT_SERVICE_NAME:
case CURLOPT_SOCKS5_GSSAPI_SERVICE:
case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
+ case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
case CURLOPT_SSH_KNOWNHOSTS:
case CURLOPT_SSH_PRIVATE_KEYFILE:
case CURLOPT_SSH_PUBLIC_KEYFILE:
}
}
- result = curl_easy_setopt(curl, tag, s);
+ result = curl_easy_setopt(easy, tag, s);
free(s);
break;
s = va_arg(arg, char *);
ccsid = va_arg(arg, unsigned int);
- pfsize = data->set.postfieldsize;
+ pfsize = easy->set.postfieldsize;
if(!s || !pfsize || ccsid == NOCONV_CCSID || ccsid == ASCII_CCSID) {
- result = curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, s);
+ result = curl_easy_setopt(easy, CURLOPT_COPYPOSTFIELDS, s);
break;
}
pfsize = convert(cp, pfsize, ASCII_CCSID, s, len, ccsid);
if(pfsize < 0) {
- free(cp);
result = CURLE_OUT_OF_MEMORY;
break;
}
- data->set.postfieldsize = pfsize; /* Replace data size. */
+ easy->set.postfieldsize = pfsize; /* Replace data size. */
s = cp;
}
- result = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, s);
- data->set.str[STRING_COPYPOSTFIELDS] = s; /* Give to library. */
+ result = curl_easy_setopt(easy, CURLOPT_POSTFIELDS, s);
+ easy->set.str[STRING_COPYPOSTFIELDS] = s; /* Give to library. */
break;
- case CURLOPT_ERRORBUFFER: /* This is an output buffer. */
default:
- result = Curl_vsetopt(curl, tag, arg);
+ if(tag / 10000 == CURLOPTTYPE_BLOB) {
+ struct curl_blob *bp = va_arg(arg, struct curl_blob *);
+ struct curl_blob blob;
+
+ ccsid = va_arg(arg, unsigned int);
+
+ if(bp && bp->data && bp->len &&
+ ccsid != NOCONV_CCSID && ccsid != ASCII_CCSID) {
+ pfsize = (curl_off_t) bp->len * MAX_CONV_EXPANSION;
+
+ if(pfsize > SIZE_MAX)
+ pfsize = SIZE_MAX;
+
+ cp = malloc(pfsize);
+
+ if(!cp) {
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ pfsize = convert(cp, pfsize, ASCII_CCSID, bp->data, bp->len, ccsid);
+
+ if(pfsize < 0) {
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ blob.data = cp;
+ blob.len = pfsize;
+ blob.flags = bp->flags | CURL_BLOB_COPY;
+ bp = &blob;
+ }
+ result = curl_easy_setopt(easy, tag, &blob);
+ break;
+ }
+ /* FALLTHROUGH */
+ case CURLOPT_ERRORBUFFER: /* This is an output buffer. */
+ result = Curl_vsetopt(easy, tag, arg);
break;
}
va_end(arg);
+ free(cp);
return result;
}
+/* ILE/RPG helper functions. */
+
char *
curl_form_long_value(long value)
{
return (const char *) name;
}
+
+/* Header API CCSID support. */
+CURLHcode
+curl_easy_header_ccsid(CURL *easy, const char *name, size_t index,
+ unsigned int origin, int request,
+ struct curl_header **hout, unsigned int ccsid)
+{
+ CURLHcode result = CURLHE_BAD_ARGUMENT;
+
+ if(name) {
+ char *s = dynconvert(ASCII_CCSID, name, -1, ccsid);
+
+ result = CURLHE_OUT_OF_MEMORY;
+ if(s) {
+ result = curl_easy_header(easy, s, index, origin, request, hout);
+ free(s);
+ }
+ }
+
+ return result;
+}