-
-
Save asakura42/64ad9ffb67c91811262d24a48640cea3 to your computer and use it in GitHub Desktop.
Simple URL fetcher in C using libcurl, can be used as a replacement for curl, if you only use it to download files.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // cc `pkg-config --cflags --libs libcurl` fetch.c -std=c99 -Os -DNDEBUG -g0 -s -Wall -o fetch | |
| #include <stdio.h> | |
| #include <getopt.h> | |
| #include <curl/curl.h> | |
| #include <stdbool.h> | |
| #include <errno.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <stdlib.h> | |
| #include <libgen.h> | |
| struct __options | |
| { | |
| bool verbose; | |
| bool quiet; | |
| char *output; | |
| int timeout; | |
| }; | |
| struct __options options; | |
| void init_options(struct __options *options) | |
| { | |
| options->output = NULL; | |
| options->quiet = 1; | |
| options->verbose = 0; | |
| options->timeout = 30; | |
| return; | |
| } | |
| static int xferinfo_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) | |
| { | |
| static int last_percent = -1; | |
| if (options.verbose && dltotal > 0) { | |
| int percent = (int)((dlnow / (double)dltotal) * 100); | |
| if (percent!= last_percent) { | |
| if (percent < 100) { | |
| printf("\rDownloading... %d%%", percent); | |
| fflush(stdout); | |
| } else { | |
| printf("\rDownloading... 100%%\n"); | |
| fflush(stdout); | |
| } | |
| last_percent = percent; | |
| } | |
| } | |
| return 0; | |
| } | |
| int download_url(char *url, char *dest_file) | |
| { | |
| CURL *handle = curl_easy_init(); | |
| if(handle == NULL) { | |
| fprintf(stderr, "Error creating CURL handle\n"); | |
| return -1; | |
| } | |
| curl_easy_setopt(handle, CURLOPT_URL, url); | |
| if(!strcmp("-", dest_file)) { | |
| curl_easy_setopt(handle, CURLOPT_WRITEDATA, stdout); | |
| } else { | |
| FILE *fp = fopen(dest_file, "w+"); | |
| if(fp == NULL) { | |
| fprintf(stderr, "Error opening file: %s\n", strerror(errno)); | |
| return -1; | |
| } | |
| curl_easy_setopt(handle, CURLOPT_WRITEDATA, fp); | |
| } | |
| curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, options.timeout); | |
| curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, xferinfo_callback); | |
| curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0); | |
| if(options.verbose) { | |
| printf("Fetching URL: %s\n", url); | |
| } | |
| int res = curl_easy_perform(handle); | |
| if(res!= CURLE_OK) { | |
| fprintf(stderr, "Error during request: %s\n", curl_easy_strerror(res)); | |
| curl_easy_cleanup(handle); | |
| return -1; | |
| } | |
| curl_easy_cleanup(handle); | |
| if(options.verbose) { | |
| printf("Done, saved to %s\n", dest_file); | |
| } | |
| return 0; | |
| } | |
| void usage(void) | |
| { | |
| printf("USAGE: fetch [-q|-v] -o [FILE] -t [TIMEOUT] URL [URL...]\n"); | |
| printf(" -t [TIMEOUT] Set timeout in seconds (default: 30)\n"); | |
| return; | |
| } | |
| int main(int argc, char **argv) | |
| { | |
| /* Init the options */ | |
| init_options(&options); | |
| /* USAGE */ | |
| if(argc <= 1) { | |
| usage(); | |
| return -1; | |
| } | |
| /* Process arguments */ | |
| int c; | |
| options.output = NULL; | |
| while((c = getopt(argc, argv, "vo:t:q"))!= -1) { | |
| switch(c) { | |
| case 'v': | |
| options.verbose = true; | |
| options.quiet = false; | |
| break; | |
| case 'q': | |
| options.quiet = true; | |
| options.verbose = false; | |
| break; | |
| case 'o': | |
| options.output = optarg; | |
| break; | |
| case 't': | |
| options.timeout = atoi(optarg); | |
| break; | |
| } | |
| } | |
| for(int i = optind; i < argc; i++) { | |
| char *url = argv[i]; | |
| char *dest_file; | |
| if(options.output == NULL) { | |
| dest_file = basename(url); | |
| } else { | |
| dest_file = options.output; | |
| } | |
| download_url(url, dest_file); | |
| } | |
| return 0; | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment