/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 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 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 <stdio.h>
#include <stdlib.h>

#include <milib.h>
#include <miptrnam.h>
#include <mih/callpgmv.h>

#ifndef CURLPGM
#define CURLPGM "CURL"
#endif

/* Variable-length string, with 16-bit length. */
struct vary2 {
  short len;
  char  string[5000];
};

/* Arguments from CL command. */
struct arguments {
  char         *pgm;            /* Program name. */
  struct vary2 *cmdargs;        /* Command line 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) {
    /* !checksrc! disable BANNEDFUNC 1 */
    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, struct 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 *)CURLPGM, 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;
}
