cleanup (void)
{
  /* Free external resources, close files, etc. */

  if (cleaned_up++)
    return; /* cleanup() must not be called twice */

  /* Close WARC file. */
  if (opt.warc_filename != 0)
    warc_close ();

  log_close ();

  if (output_stream && output_stream != stderr)
    {
      FILE *fp = output_stream;
      output_stream = NULL;
      if (fclose (fp) == EOF)
        inform_exit_status (CLOSEFAILED);
    }

  /* No need to check for error because Wget flushes its output (and
     checks for errors) after any data arrives.  */

  /* We're exiting anyway so there's no real need to call free()
     hundreds of times.  Skipping the frees will make Wget exit
     faster.
   *
     However, when detecting leaks, it's crucial to free() everything
     because then you can find the real leaks, i.e. the allocated
     memory which grows with the size of the program.  */

#if defined DEBUG_MALLOC || defined TESTING
  convert_cleanup ();
  res_cleanup ();
  http_cleanup ();
  cleanup_html_url ();
  spider_cleanup ();
  host_cleanup ();
  log_cleanup ();
  netrc_cleanup ();

  xfree (opt.choose_config);
  xfree (opt.lfilename);
  xfree (opt.dir_prefix);
  xfree (opt.input_filename);
#ifdef HAVE_METALINK
  xfree (opt.input_metalink);
  xfree (opt.preferred_location);
#endif
  xfree (opt.output_document);
  xfree (opt.default_page);
  if (opt.regex_type == regex_type_posix)
    {
      if (opt.acceptregex)
        regfree (opt.acceptregex);
      if (opt.rejectregex)
        regfree (opt.rejectregex);
    }
  xfree (opt.acceptregex);
  xfree (opt.rejectregex);
  xfree (opt.acceptregex_s);
  xfree (opt.rejectregex_s);
  free_vec (opt.accepts);
  free_vec (opt.rejects);
  free_vec ((char **)opt.excludes);
  free_vec ((char **)opt.includes);
  free_vec (opt.domains);
  free_vec (opt.exclude_domains);
  free_vec (opt.follow_tags);
  free_vec (opt.ignore_tags);
  xfree (opt.progress_type);
  xfree (opt.warc_filename);
  xfree (opt.warc_tempdir);
  xfree (opt.warc_cdx_dedup_filename);
  xfree (opt.ftp_user);
  xfree (opt.ftp_passwd);
  xfree (opt.ftp_proxy);
  xfree (opt.https_proxy);
  xfree (opt.http_proxy);
  free_vec (opt.no_proxy);
  xfree (opt.proxy_user);
  xfree (opt.proxy_passwd);
  xfree (opt.useragent);
  xfree (opt.referer);
  xfree (opt.http_user);
  xfree (opt.http_passwd);
  xfree (opt.dot_style);
  free_vec (opt.user_headers);
  free_vec (opt.warc_user_headers);
# ifdef HAVE_SSL
  xfree (opt.cert_file);
  xfree (opt.private_key);
  xfree (opt.ca_directory);
  xfree (opt.ca_cert);
  xfree (opt.crl_file);
  xfree (opt.pinnedpubkey);
  xfree (opt.random_file);
  xfree (opt.egd_file);
# endif
  xfree (opt.bind_address);
  xfree (opt.cookies_input);
  xfree (opt.cookies_output);
  xfree (opt.user);
  xfree (opt.passwd);
  xfree (opt.base_href);
  xfree (opt.method);
  xfree (opt.post_file_name);
  xfree (opt.post_data);
  xfree (opt.body_data);
  xfree (opt.body_file);
  xfree (opt.rejected_log);
  xfree (opt.use_askpass);
  xfree (opt.retry_on_http_error);

  xfree (opt.encoding_remote);
  xfree (opt.locale);
  xfree (opt.hsts_file);

  xfree (opt.wgetrcfile);
  xfree (opt.homedir);
  xfree (exec_name);
  xfree (program_argstring);
  ptimer_destroy (timer); timer = NULL;

#ifdef HAVE_LIBCARES
#include <ares.h>
  {
    extern ares_channel ares;

    xfree (opt.bind_dns_address);
    xfree (opt.dns_servers);
    ares_destroy (ares);
    ares_library_cleanup ();
  }
#endif

  quotearg_free ();

#endif /* DEBUG_MALLOC || TESTING */
}