Commit 99542429 authored by Colin Hogben's avatar Colin Hogben Committed by Daniel Stenberg
Browse files

Generate lists and use symbols in --libcurl code output.

This patch improves the output of curl's --libcurl option by
generating code which builds curl_httppost and curl_slist lists, and
uses symbolic names for enum and flag values.  Variants of the
my_setopt macro in tool_setopt.h are added in order to pass extra type
information to the code-generation step in tool_setopt.c.

If curl is configured with --disable-libcurl-option then the macros
call curl_easy_setopt directly.
parent 2f1ad7d6
Loading
Loading
Loading
Loading
+138 −24
Original line number Diff line number Diff line
@@ -37,8 +37,13 @@

/* global variable definitions, for easy-interface source code generation */

struct curl_slist *easysrc = NULL;
struct curl_slist *easysrc_remarks = NULL;
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 **********",
@@ -50,8 +55,117 @@ static const char *const srchead[]={
  "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(0)

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]) != '\0'); 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)
{
@@ -76,40 +190,40 @@ void dumpeasysrc(struct Configurable *config)
      for(i=0; ((c = srchead[i]) != '\0'); i++)
        fprintf(out, "%s\n", c);

      ptr = easysrc;
      while(ptr) {
      /* Declare variables used for complex setopt values */
      for(ptr=easysrc_decl; ptr; ptr = ptr->next)
        fprintf(out, "  %s\n", ptr->data);
        ptr = ptr->next;
      }

      ptr = easysrc_remarks;
      if(ptr) {
        fprintf(out,
                "\n  /* Here is a list of options the curl code"
                " used that cannot get generated\n"
                "     as source easily. You may select to either"
                " not use them or implement\n     them yourself.\n"
                "\n");
        while(ptr) {

      /* 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);
          ptr = ptr->next;
        }
        fprintf(out, "\n  */\n");
        else {
          fprintf(out, "\n");
        }
      }

      for(ptr=easysrc_clean; ptr; ptr = ptr->next)
        fprintf(out, "  %s\n", ptr->data);

      for(i=0; ((c = srcend[i]) != '\0'); i++)
        fprintf(out, "%s\n", c);

      fprintf(out,
              "  return (int)ret;\n"
              "}\n"
              "/**** End of sample code ****/\n");
      if(fopened)
        fclose(out);
    }
  }

  curl_slist_free_all(easysrc_remarks);
  curl_slist_free_all(easysrc);
  easysrc_remarks = NULL;
  easysrc = NULL;
  easysrc_free();
}

#endif /* CURL_DISABLE_LIBCURL_OPTION */
+14 −4
Original line number Diff line number Diff line
@@ -26,12 +26,22 @@

/* global variable declarations, for easy-interface source code generation */

extern struct curl_slist *easysrc;
extern struct curl_slist *easysrc_remarks;
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_LIBCIRL_CMD */
#endif /* CURL_DISABLE_LIBCURL_OPTION */

#endif /* HEADER_CURL_TOOL_EASYSRC_H */
+27 −30
Original line number Diff line number Diff line
@@ -355,11 +355,9 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
  }

#ifndef CURL_DISABLE_LIBCURL_OPTION
  /* This is the first entry added to easysrc and it initializes the slist */
  easysrc = curl_slist_append(easysrc, "CURL *hnd = curl_easy_init();");
  if(!easysrc) {
  res = easysrc_init();
  if(res) {
    helpf(config->errors, "out of memory\n");
    res = CURLE_OUT_OF_MEMORY;
    goto quit_curl;
  }
#endif
@@ -835,25 +833,25 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])

          /* new in libcurl 7.5 */
          if(config->proxy)
            my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver);
            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(curl, CURLOPT_PROXYTYPE, config->socksver);
            my_setopt_enum(curl, CURLOPT_PROXYTYPE, config->socksver);
          }

          /* new in libcurl 7.10.6 */
          if(config->proxyanyauth)
            my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
            my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
          else if(config->proxynegotiate)
            my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
            my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
          else if(config->proxyntlm)
            my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
            my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
          else if(config->proxydigest)
            my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
            my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
          else if(config->proxybasic)
            my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
            my_setopt_flags(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);

          /* new in libcurl 7.19.4 */
          my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
@@ -896,7 +894,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
                      config->postfieldsize);
            break;
          case HTTPREQ_POST:
            my_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
            my_setopt_httppost(curl, CURLOPT_HTTPPOST, config->httppost);
            break;
          default:
            break;
@@ -905,18 +903,18 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
          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(curl, CURLOPT_HTTPHEADER, config->headers);
          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(curl, CURLOPT_HTTP_VERSION, 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(curl, CURLOPT_HTTPAUTH, config->authtype);
            my_setopt_flags(curl, CURLOPT_HTTPAUTH, config->authtype);

          /* curl 7.19.1 (the 301 version existed in 7.18.2) */
          my_setopt(curl, CURLOPT_POSTREDIR, config->post301 |
@@ -1011,9 +1009,9 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
        }

        my_setopt(curl, CURLOPT_CRLF, config->crlf);
        my_setopt(curl, CURLOPT_QUOTE, config->quote);
        my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
        my_setopt(curl, CURLOPT_PREQUOTE, config->prequote);
        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)
        {
@@ -1034,8 +1032,8 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
        }
#endif

        my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
        my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
        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);
@@ -1054,7 +1052,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
        }

        /* new in libcurl 7.6.2: */
        my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
        my_setopt_slist(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);

        /* new in libcurl 7.7: */
        my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
@@ -1118,7 +1116,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])

        /* new in curl 7.16.1 */
        if(config->ftp_ssl_ccc)
          my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);
          my_setopt_enum(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);

#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
        {
@@ -1191,16 +1189,16 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
          my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);

        if(config->mail_rcpt)
          my_setopt(curl, CURLOPT_MAIL_RCPT, 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(curl, CURLOPT_PROTOCOLS, config->proto);
          my_setopt_flags(curl, CURLOPT_PROTOCOLS, config->proto);
        if(config->proto_redir_present)
          my_setopt(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);
          my_setopt_flags(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir);

        if((urlnode->flags & GETOUT_USEREMOTE)
           && config->content_disposition) {
@@ -1216,7 +1214,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])

        if(config->resolve)
          /* new in 7.21.3 */
          my_setopt(curl, CURLOPT_RESOLVE, config->resolve);
          my_setopt_slist(curl, CURLOPT_RESOLVE, config->resolve);

        /* new in 7.21.4 */
        if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) {
@@ -1252,8 +1250,8 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
        retrystart = tvnow();

#ifndef CURL_DISABLE_LIBCURL_OPTION
        if(!curl_slist_append(easysrc, "ret = curl_easy_perform(hnd);")) {
          res = CURLE_OUT_OF_MEMORY;
        res = easysrc_perform();
        if(res) {
          goto show_error;
        }
#endif
@@ -1580,8 +1578,7 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[])
    config->easy = curl = NULL;
  }
#ifndef CURL_DISABLE_LIBCURL_OPTION
  if(easysrc)
    curl_slist_append(easysrc, "curl_easy_cleanup(hnd);");
  easysrc_cleanup();
#endif

  /* Close function-local opened file descriptors */
+374 −29

File changed.

Preview size limit exceeded, changes collapsed.

+62 −1
Original line number Diff line number Diff line
@@ -35,8 +35,45 @@

#ifndef CURL_DISABLE_LIBCURL_OPTION

/* Associate symbolic names with option values */
typedef struct {
  const char *name;
  long value;
} NameValue;

extern const NameValue setopt_nv_CURLPROXY[];
extern const NameValue setopt_nv_CURLAUTH[];
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[];

/* 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_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, ...);

@@ -46,11 +83,23 @@ CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config,
#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_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
#else /* CURL_DISABLE_LIBCURL_OPTION */

/* No --libcurl, so pass options directly to library */

@@ -60,6 +109,18 @@ CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config,
#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_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)