diff --git a/lib/setup-os400.h b/lib/setup-os400.h index 7d8967b15..53e91777e 100644 --- a/lib/setup-os400.h +++ b/lib/setup-os400.h @@ -34,6 +34,9 @@ /* No OS/400 header file defines u_int32_t. */ typedef unsigned long u_int32_t; +/* OS/400 has no idea of a tty! */ +#define isatty(fd) 0 + /* System API wrapper prototypes & definitions to support ASCII parameters. */ diff --git a/packages/Makefile.am b/packages/Makefile.am index 5c262dd5e..9fb6637ff 100644 --- a/packages/Makefile.am +++ b/packages/Makefile.am @@ -28,6 +28,8 @@ EXTRA_DIST = README.md \ OS400/rpg-examples \ OS400/ccsidcurl.c \ OS400/ccsidcurl.h \ + OS400/curlcl.c \ + OS400/curlmain.c \ OS400/curl.inc.in \ OS400/initscript.sh \ OS400/make-include.sh \ @@ -36,7 +38,8 @@ EXTRA_DIST = README.md \ OS400/make-tests.sh \ OS400/makefile.sh \ OS400/os400sys.c \ - OS400/os400sys.h + OS400/os400sys.h \ + OS400/curl.cmd CHECKSRC = $(CS_$(V)) CS_0 = @echo " RUN " $@; diff --git a/packages/OS400/README.OS400 b/packages/OS400/README.OS400 index 59627d7bd..e28dedb36 100644 --- a/packages/OS400/README.OS400 +++ b/packages/OS400/README.OS400 @@ -374,3 +374,16 @@ _ Since V7R4M0, procedure overloading is used to emulate limited "vararg-like" is provided for that purpose: this allows storing a long value in the curl_forms array. Please note the form API is deprecated and the MIME API should be used instead. + + +CLI tool: + + The build system provides it as a bound program, an IFS link to it and a +simple CL command. The latter however is not able to provide a different +parameter for each option since there are too many of those; instead, +parameters are entered in a single field subject to quoting and escaping, in +the same form as expected by the standard CLI program. + Care must be taken about the program output encoding: by default, it is sent +to the standard output and is thus subject to transcoding. It is therefore +recommended to use option "--output" to redirect output to a specific IFS file. +Similar problems may occur about the standard input encoding. diff --git a/packages/OS400/curl.cmd b/packages/OS400/curl.cmd new file mode 100644 index 000000000..822f4db20 --- /dev/null +++ b/packages/OS400/curl.cmd @@ -0,0 +1,32 @@ +/*****************************************************************************/ +/* _ _ ____ _ */ +/* Project ___| | | | _ \| | */ +/* / __| | | | |_) | | */ +/* | (__| |_| | _ <| |___ */ +/* \___|\___/|_| \_\_____| */ +/* */ +/* Copyright (C) Daniel Stenberg, , 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 https://curl.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. */ +/* */ +/* SPDX-License-Identifier: curl */ +/* */ +/* */ +/*****************************************************************************/ + +/* Use program CURLCL as interface to the curl command line tool */ + + CMD PROMPT('File transfer utility') + + PARM KWD(CMDARGS) TYPE(*CHAR) LEN(5000) VARY(*YES *INT2) + + CASE(*MIXED) EXPR(*YES) MIN(1) + + PROMPT('Curl command arguments') diff --git a/packages/OS400/curlcl.c b/packages/OS400/curlcl.c new file mode 100644 index 000000000..d4855d806 --- /dev/null +++ b/packages/OS400/curlcl.c @@ -0,0 +1,176 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , 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 https://curl.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. + * + * SPDX-License-Identifier: curl + * + * + ***************************************************************************/ + +/* CL interface program to curl cli tool. */ + +#include +#include + +#include +#include +#include + + +/* Variable-length string, with 16-bit length. */ +typedef struct { + short len; + char string[5000]; +} vary2; + + +/* Arguments from CL command. */ +typedef struct { + char * pgm; /* Program name. */ + vary2 * cmdargs; /* Command line arguments. */ +} arguments; + + +static int +is_ifs(char c) +{ + return c == ' ' || c == '\t' || c == '\r' || c == '\n'; +} + +static int +parse_command_line(const char *cmdargs, size_t len, + size_t *argc, char **argv, + size_t *argsize, char *argbuf) +{ + const char *endline = cmdargs + len; + char quote = '\0'; + int inarg = 0; + + *argc = 0; + *argsize = 0; + + while(cmdargs < endline) { + char c = *cmdargs++; + + if(!inarg) { + /* Skip argument separator. */ + if(is_ifs(c)) + continue; + + /* Start a new argument. */ + ++*argc; + if(argv) + *argv++ = argbuf; + inarg = 1; + } + + /* Check for quoting end. */ + if(quote && quote == c) { + quote = '\0'; + continue; + } + + /* Check for backslash-escaping. */ + if(quote != '\'' && c == '\\') { + if(cmdargs >= endline) { + fputs("Trailing backslash in command\n", stderr); + return -1; + } + c = *cmdargs++; + } + else if(!quote && is_ifs(c)) { /* Check for end of argument. */ + inarg = 0; + c = '\0'; /* Will store a string terminator. */ + } + + /* Store argument character and count it. */ + if(argbuf) + *argbuf++ = c; + ++*argsize; + } + + if(quote) { + fprintf(stderr, "Unterminated quote: %c\n", quote); + return -1; + } + + /* Terminate last argument. */ + if(inarg) { + if(argbuf) + *argbuf = '\0'; + ++*argsize; + } + + /* Terminate argument list. */ + if(argv) + *argv = NULL; + + return 0; +} + + +int +main(int argsc, arguments *args) +{ + size_t argc; + char **argv; + size_t argsize; + int i; + int exitcode; + char library[11]; + + /* Extract current program library name. */ + for(i = 0; i < 10; i++) { + char c = args->pgm[i]; + + if(!c || c == '/') + break; + + library[i] = c; + } + library[i] = '\0'; + + /* Measure arguments size. */ + exitcode = parse_command_line(args->cmdargs->string, args->cmdargs->len, + &argc, NULL, &argsize, NULL); + + if(!exitcode) { + /* Allocate space for parsed arguments. */ + argv = (char **) malloc((argc + 1) * sizeof(*argv) + argsize); + if(!argv) { + fputs("Memory allocation error\n", stderr); + exitcode = -2; + } + else { + _SYSPTR pgmptr = rslvsp(WLI_PGM, (char *) "CURL", library, _AUTH_NONE); + _LU_Work_Area_T *luwrka = (_LU_Work_Area_T *) _LUWRKA(); + + parse_command_line(args->cmdargs->string, args->cmdargs->len, + &argc, argv, &argsize, (char *) (argv + argc + 1)); + + /* Call program. */ + _CALLPGMV((void *) &pgmptr, argv, argc); + exitcode = luwrka->LU_RC; + + free(argv); + } + } + + return exitcode; +} diff --git a/packages/OS400/curlmain.c b/packages/OS400/curlmain.c new file mode 100644 index 000000000..44fc84e08 --- /dev/null +++ b/packages/OS400/curlmain.c @@ -0,0 +1,123 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , 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 https://curl.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. + * + * SPDX-License-Identifier: curl + * + * + ***************************************************************************/ + +/* + * QADRT/QADRTMAIN2 substitution program. + * This is needed because the IBM-provided QADRTMAIN2 does not + * properly translate arguments by default or if no locale is provided. + */ + +#include +#include +#include +#include +#include + +/* Do not use qadrt.h since it defines unneeded static procedures. */ +extern void QadrtInit(void); +extern int QadrtFreeConversionTable(void); +extern int QadrtFreeEnviron(void); +extern char * setlocale_a(int, const char *); + + +/* The ASCII main program. */ +extern int main_a(int argc, char * * argv); + +/* Global values of original EBCDIC arguments. */ +int ebcdic_argc; +char ** ebcdic_argv; + + +int +main(int argc, char **argv) + +{ + int i; + int j; + iconv_t cd; + size_t bytecount = 0; + char * inbuf; + char * outbuf; + size_t inbytesleft; + size_t outbytesleft; + char dummybuf[128]; + char tocode[32]; + char fromcode[32]; + + ebcdic_argc = argc; + ebcdic_argv = argv; + + /* Build the encoding converter. */ + strncpy(tocode, "IBMCCSID01208", sizeof tocode); /* Use UTF-8. */ + strncpy(fromcode, "IBMCCSID000000000010", sizeof fromcode); + cd = iconv_open(tocode, fromcode); + + /* Measure the arguments. */ + for(i = 0; i < argc; i++) { + inbuf = argv[i]; + do { + inbytesleft = 0; + outbuf = dummybuf; + outbytesleft = sizeof dummybuf; + j = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + bytecount += outbuf - dummybuf; + } while(j == -1 && errno == E2BIG); + + /* Reset the shift state. */ + iconv(cd, NULL, &inbytesleft, &outbuf, &outbytesleft); + } + + /* Allocate memory for the ASCII arguments and vector. */ + argv = (char **) malloc((argc + 1) * sizeof *argv + bytecount); + + /* Build the vector and convert argument encoding. */ + outbuf = (char *) (argv + argc + 1); + outbytesleft = bytecount; + + for(i = 0; i < argc; i++) { + argv[i] = outbuf; + inbuf = ebcdic_argv[i]; + inbytesleft = 0; + iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + iconv(cd, NULL, &inbytesleft, &outbuf, &outbytesleft); + } + + iconv_close(cd); + argv[argc] = NULL; + + /* Try setting the locale regardless of QADRT_ENV_LOCALE. */ + setlocale_a(LC_ALL, ""); + + /* Call the program. */ + i = main_a(argc, argv); + + /* Clean-up allocated items. */ + free((char *) argv); + QadrtFreeConversionTable(); + QadrtFreeEnviron(); + + /* Terminate. */ + return i; +} diff --git a/packages/OS400/initscript.sh b/packages/OS400/initscript.sh index d275146f1..ef596c4e2 100755 --- a/packages/OS400/initscript.sh +++ b/packages/OS400/initscript.sh @@ -80,7 +80,6 @@ setenv OUTPUT '*NONE' # Compilation output option. setenv TGTRLS '*CURRENT' # Target OS release. setenv IFSDIR '/curl' # Installation IFS directory. setenv QADRTDIR '/QIBM/ProdData/qadrt' # QADRT IFS directory. -setenv QADRTLIB 'QADRT' # QADRT object library. # Define ZLIB availability and locations. @@ -236,7 +235,7 @@ make_module() CMD="${CMD} OPTIMIZE(${OPTIMIZE})" CMD="${CMD} DBGVIEW(${DEBUG})" - DEFINES="${3} BUILDING_LIBCURL 'qadrt_use_inline'" + DEFINES="${3} 'qadrt_use_inline'" if [ "${WITH_ZLIB}" != "0" ] then DEFINES="${DEFINES} HAVE_LIBZ" @@ -270,6 +269,7 @@ db2_name() tr 'a-z-' 'A-Z_' | sed -e 's/\..*//' \ -e 's/^CURL_*/C/' \ + -e 's/^TOOL_*/T/' \ -e 's/^\(.\).*\(.........\)$/\1\2/' fi } @@ -288,3 +288,26 @@ versioned_copy() -e "s/@LIBCURL_TIMESTAMP@/${LIBCURL_TIMESTAMP}/g" \ < "${1}" > "${2}" } + + +# Get definitions from a make file. +# The `sed' statement works as follows: +# - Join \nl-separated lines. +# - Retain only lines that begins with "identifier =". +# - Turn these lines into shell variable assignments. + +get_make_vars() + +{ + eval "`sed -e ': begin' \ + -e '/\\\\$/{' \ + -e 'N' \ + -e 's/\\\\\\n/ /' \ + -e 'b begin' \ + -e '}' \ + -e '/^[A-Za-z_][A-Za-z0-9_]*[[:space:]]*=/!d' \ + -e 's/[[:space:]]*=[[:space:]]*/=/' \ + -e 's/=\\(.*[^[:space:]]\\)[[:space:]]*$/=\\"\\1\\"/' \ + -e 's/\\\$(\\([^)]*\\))/\${\\1}/g' \ + < \"${1}\"`" +} diff --git a/packages/OS400/make-lib.sh b/packages/OS400/make-lib.sh index 55e7b6feb..7ad16109b 100755 --- a/packages/OS400/make-lib.sh +++ b/packages/OS400/make-lib.sh @@ -44,37 +44,26 @@ echo '#pragma comment(user, "libcurl version '"${LIBCURL_VERSION}"'")' > os400.c echo '#pragma comment(user, __DATE__)' >> os400.c echo '#pragma comment(user, __TIME__)' >> os400.c echo '#pragma comment(copyright, "Copyright (C) Daniel Stenberg et al. OS/400 version by P. Monnerat")' >> os400.c -make_module OS400 os400.c +make_module OS400 os400.c BUILDING_LIBCURL LINK= # No need to rebuild service program yet. MODULES= -# Get source list. +# Get source list (CSOURCES variable). -sed -e ':begin' \ - -e '/\\$/{' \ - -e 's/\\$/ /' \ - -e 'N' \ - -e 'bbegin' \ - -e '}' \ - -e 's/\n//g' \ - -e 's/[[:space:]]*$//' \ - -e 's/^\([A-Za-z][A-Za-z0-9_]*\)[[:space:]]*=[[:space:]]*\(.*\)/\1="\2"/' \ - -e 's/\$(\([A-Za-z][A-Za-z0-9_]*\))/${\1}/g' \ - < Makefile.inc > tmpscript.sh -. ./tmpscript.sh +get_make_vars Makefile.inc # Compile the sources into modules. INCLUDES="'`pwd`'" -make_module OS400SYS "${SCRIPTDIR}/os400sys.c" -make_module CCSIDCURL "${SCRIPTDIR}/ccsidcurl.c" +make_module OS400SYS "${SCRIPTDIR}/os400sys.c" BUILDING_LIBCURL +make_module CCSIDCURL "${SCRIPTDIR}/ccsidcurl.c" BUILDING_LIBCURL for SRC in ${CSOURCES} do MODULE=`db2_name "${SRC}"` - make_module "${MODULE}" "${SRC}" + make_module "${MODULE}" "${SRC}" BUILDING_LIBCURL done diff --git a/packages/OS400/make-src.sh b/packages/OS400/make-src.sh index 62654c36a..b66ea83e2 100755 --- a/packages/OS400/make-src.sh +++ b/packages/OS400/make-src.sh @@ -23,5 +23,76 @@ # ########################################################################### # -# -# Not implemented yet on OS/400. +# Command line interface tool compilation script for the OS/400. + +SCRIPTDIR=`dirname "${0}"` +. "${SCRIPTDIR}/initscript.sh" +cd "${TOPDIR}/src" + + +# Get source lists. +# CURL_CFILES are in the current directory. +# CURLX_CFILES are in the lib directory and need to be recompiled because +# some function names change using macros. + +get_make_vars Makefile.inc + + +# Compile the sources into modules. + +LINK= +MODULES= +INCLUDES="'${TOPDIR}/lib'" + +for SRC in ${CURLX_CFILES} +do MODULE=`db2_name "${SRC}"` + MODULE=`db2_name "X${MODULE}"` + make_module "${MODULE}" "${SRC}" +done + +for SRC in ${CURL_CFILES} +do MODULE=`db2_name "${SRC}"` + make_module "${MODULE}" "${SRC}" +done + + +# Link modules into program. + +MODULES="`echo \"${MODULES}\" | sed \"s/[^ ][^ ]*/${TARGETLIB}\/&/g\"`" +CMD="CRTPGM PGM(${TARGETLIB}/CURL)" +CMD="${CMD} ENTMOD(${TARGETLIB}/CURLMAIN)" +CMD="${CMD} MODULE(${MODULES})" +CMD="${CMD} BNDSRVPGM(${TARGETLIB}/${SRVPGM} QADRTTS)" +CMD="${CMD} TGTRLS(${TGTRLS})" +CLcommand "${CMD}" + + +# Create the IFS command. + +IFSBIN="${IFSDIR}/bin" + +if action_needed "${IFSBIN}" +then mkdir -p "${IFSBIN}" +fi + +rm -f "${IFSBIN}/curl" +ln -s "/QSYS.LIB/${TARGETLIB}.LIB/CURL.PGM" "${IFSBIN}/curl" + + +# Create the CL interface program. + +if action_needed "${LIBIFSNAME}/CURLCL.PGM" "${SCRIPTDIR}/curlcl.c" +then CMD="CRTBNDC PGM(${TARGETLIB}/CURLCL)" + CMD="${CMD} SRCSTMF('${SCRIPTDIR}/curlcl.c')" + CMD="${CMD} TGTCCSID(${TGTCCSID})" + CLcommand "${CMD}" +fi + + +# Create the CL command. + +if action_needed "${LIBIFSNAME}/CURL.CMD" "${SCRIPTDIR}/curl.cmd" +then CMD="CRTCMD CMD(${TARGETLIB}/CURL) PGM(${TARGETLIB}/CURLCL)" + CMD="${CMD} SRCSTMF('${SCRIPTDIR}/curl.cmd')" + CLcommand "${CMD}" +fi diff --git a/packages/OS400/make-tests.sh b/packages/OS400/make-tests.sh index a5a472cf1..470fb5101 100755 --- a/packages/OS400/make-tests.sh +++ b/packages/OS400/make-tests.sh @@ -40,24 +40,8 @@ cd "${TOPDIR}/tests" cd libtest # Get definitions from the Makefile.inc file. -# The `sed' statement works as follows: -# _ Join \nl-separated lines. -# _ Retain only lines that begins with "identifier =". -# _ Turn these lines into shell variable assignments. -eval "`sed -e ': begin' \ - -e '/\\\\$/{' \ - -e 'N' \ - -e 's/\\\\\\n/ /' \ - -e 'b begin' \ - -e '}' \ - -e '/^[A-Za-z_][A-Za-z0-9_]*[[:space:]]*[=]/b keep' \ - -e 'd' \ - -e ': keep' \ - -e 's/[[:space:]]*=[[:space:]]*/=/' \ - -e 's/=\\(.*[^[:space:]]\\)[[:space:]]*$/=\\"\\1\\"/' \ - -e 's/\\$(\\([^)]*\\))/${\\1}/g' \ - < Makefile.inc`" +get_make_vars Makefile.inc # Special case: redefine chkhostname compilation parameters. @@ -128,7 +112,7 @@ do DB2PGM=`db2_name "${PGM}"` MODULES="`echo \"${MODULES}\" | sed \"s/[^ ][^ ]*/${TARGETLIB}\/&/g\"`" CMD="CRTPGM PGM(${TARGETLIB}/${DB2PGM})" - CMD="${CMD} ENTMOD(${QADRTLIB}/QADRTMAIN2)" + CMD="${CMD} ENTMOD(${TARGETLIB}/CURLMAIN)" CMD="${CMD} MODULE(${MODULES})" CMD="${CMD} BNDSRVPGM(${TARGETLIB}/${SRVPGM} QADRTTS)" CMD="${CMD} TGTRLS(${TGTRLS})" diff --git a/packages/OS400/makefile.sh b/packages/OS400/makefile.sh index 70399cb99..3d659645d 100755 --- a/packages/OS400/makefile.sh +++ b/packages/OS400/makefile.sh @@ -101,6 +101,20 @@ do MEMBER="`basename \"${EXAMPLE}\"`" done +# Compile the QADRTMAIN2 replacement module. + +if action_needed "${LIBIFSNAME}/CURLMAIN.MODULE" "${SCRIPTDIR}/curlmain.c" +then CMD="CRTCMOD MODULE(${TARGETLIB}/CURLMAIN)" + CMD="${CMD} SRCSTMF('${SCRIPTDIR}/curlmain.c')" + CMD="${CMD} SYSIFCOPT(*IFS64IO) LOCALETYPE(*LOCALE) FLAG(10)" + CMD="${CMD} TGTCCSID(${TGTCCSID}) TGTRLS(${TGTRLS})" + CMD="${CMD} OUTPUT(${OUTPUT})" + CMD="${CMD} OPTIMIZE(${OPTIMIZE})" + CMD="${CMD} DBGVIEW(${DEBUG})" + CLcommand "${CMD}" +fi + + # Build in each directory. # for SUBDIR in include lib src tests