Add -m switch
Disaply size of downloaded file in an human way
This commit is contained in:
		
							
								
								
									
										141
									
								
								gget.c
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								gget.c
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
  Copyright 2014 Grégory Soutadé
 | 
			
		||||
  Copyright 2014-2016 Grégory Soutadé
 | 
			
		||||
 | 
			
		||||
  This file is part of gget.
 | 
			
		||||
 | 
			
		||||
@@ -86,6 +86,7 @@ static int get_console_width()
 | 
			
		||||
typedef struct {
 | 
			
		||||
    curl_off_t dltotal;
 | 
			
		||||
    curl_off_t dlnow;
 | 
			
		||||
    curl_off_t dllast;
 | 
			
		||||
    unsigned speed;
 | 
			
		||||
} stats_t ;
 | 
			
		||||
 | 
			
		||||
@@ -101,6 +102,7 @@ typedef struct {
 | 
			
		||||
    unsigned already_downloaded;
 | 
			
		||||
    unsigned start;
 | 
			
		||||
    unsigned end;
 | 
			
		||||
    unsigned max_chunk_size;
 | 
			
		||||
    curl_off_t max_speed;
 | 
			
		||||
    stats_t* stats;
 | 
			
		||||
} transfert_t;
 | 
			
		||||
@@ -216,8 +218,8 @@ static int progress_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl
 | 
			
		||||
 | 
			
		||||
    curl_easy_getinfo(t->curl, CURLINFO_SPEED_DOWNLOAD, &speed_d);
 | 
			
		||||
 | 
			
		||||
    t->stats[t->id].dltotal = dltotal + t->already_downloaded;
 | 
			
		||||
    t->stats[t->id].dlnow = dlnow + t->already_downloaded;
 | 
			
		||||
    t->stats[t->id].dlnow += (dlnow - t->stats[t->id].dllast);
 | 
			
		||||
    t->stats[t->id].dllast = dlnow;
 | 
			
		||||
    t->stats[t->id].speed = speed_d;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
@@ -226,14 +228,12 @@ static int progress_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl
 | 
			
		||||
void* do_transfert(transfert_t* t)
 | 
			
		||||
{
 | 
			
		||||
    CURLcode res;
 | 
			
		||||
    char range[50];
 | 
			
		||||
 | 
			
		||||
    snprintf(range, sizeof(range), "%u-%u", t->start, t->end);
 | 
			
		||||
 | 
			
		||||
    char range[64];
 | 
			
		||||
    unsigned start, end, chunk_size;
 | 
			
		||||
    
 | 
			
		||||
    curl_easy_setopt(t->curl, CURLOPT_USERAGENT, t->user_agent);
 | 
			
		||||
    curl_easy_setopt(t->curl, CURLOPT_URL, t->url);
 | 
			
		||||
    curl_easy_setopt(t->curl, CURLOPT_FOLLOWLOCATION, 1L);
 | 
			
		||||
    curl_easy_setopt(t->curl, CURLOPT_RANGE, range);
 | 
			
		||||
 | 
			
		||||
    if (t->max_speed)
 | 
			
		||||
        curl_easy_setopt(t->curl, CURLOPT_MAX_RECV_SPEED_LARGE, t->max_speed);
 | 
			
		||||
@@ -248,13 +248,37 @@ void* do_transfert(transfert_t* t)
 | 
			
		||||
    curl_easy_setopt(t->curl, CURLOPT_XFERINFOFUNCTION, progress_cb);
 | 
			
		||||
    curl_easy_setopt(t->curl, CURLOPT_XFERINFODATA, t);
 | 
			
		||||
 | 
			
		||||
    /* Perform the request, res will get the return code */ 
 | 
			
		||||
    res = curl_easy_perform(t->curl);
 | 
			
		||||
    /* Check for errors */ 
 | 
			
		||||
    if(res != CURLE_OK)
 | 
			
		||||
        fprintf(stderr, "curl_easy_perform() failed: %s\n",
 | 
			
		||||
                curl_easy_strerror(res));
 | 
			
		||||
    start = t->start;
 | 
			
		||||
    if (t->max_chunk_size && (t->end - t->start) > t->max_chunk_size)
 | 
			
		||||
        chunk_size = t->max_chunk_size;
 | 
			
		||||
    else
 | 
			
		||||
        chunk_size = t->end - t->start;
 | 
			
		||||
    end = start + chunk_size;
 | 
			
		||||
 | 
			
		||||
    while (start < t->end)
 | 
			
		||||
    {
 | 
			
		||||
        snprintf(range, sizeof(range), "%u-%u", start, end);
 | 
			
		||||
        curl_easy_setopt(t->curl, CURLOPT_RANGE, range);
 | 
			
		||||
 | 
			
		||||
        /* Perform the request, res will get the return code */
 | 
			
		||||
        res = curl_easy_perform(t->curl);
 | 
			
		||||
        /* Check for errors */ 
 | 
			
		||||
        if(res != CURLE_OK)
 | 
			
		||||
        {
 | 
			
		||||
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
 | 
			
		||||
                    curl_easy_strerror(res));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        start += chunk_size + 1;
 | 
			
		||||
        if (t->max_chunk_size && (t->end - start) > t->max_chunk_size)
 | 
			
		||||
            chunk_size = t->max_chunk_size;
 | 
			
		||||
        else
 | 
			
		||||
            chunk_size = t->end - start;
 | 
			
		||||
        end = start + chunk_size;
 | 
			
		||||
        t->stats[t->id].dllast = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -262,7 +286,7 @@ static int configure_transfert(int id, transfert_t* t,
 | 
			
		||||
                               char* url, char* filename,
 | 
			
		||||
                               unsigned start, unsigned end,
 | 
			
		||||
                               unsigned max_speed, char* user_agent,
 | 
			
		||||
                               int* exists)
 | 
			
		||||
                               unsigned max_chunk_size, int* exists)
 | 
			
		||||
{
 | 
			
		||||
    // filename + . + number + \0
 | 
			
		||||
    unsigned filename_size = strlen(filename)+1+3+1;
 | 
			
		||||
@@ -284,6 +308,7 @@ static int configure_transfert(int id, transfert_t* t,
 | 
			
		||||
    t->end = end;
 | 
			
		||||
    t->max_speed = max_speed;
 | 
			
		||||
    t->user_agent = user_agent;
 | 
			
		||||
    t->max_chunk_size = max_chunk_size;
 | 
			
		||||
 | 
			
		||||
    if (stat(t->tmp_filename, &s))
 | 
			
		||||
    {
 | 
			
		||||
@@ -371,6 +396,7 @@ static int get_file_info(char* url, char* user_agent,
 | 
			
		||||
    curl_easy_setopt(curl, CURLOPT_URL, url);
 | 
			
		||||
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
 | 
			
		||||
    curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
 | 
			
		||||
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
 | 
			
		||||
    if (!quiet)
 | 
			
		||||
        curl_easy_setopt(curl, CURLOPT_HEADER, 1L);
 | 
			
		||||
 | 
			
		||||
@@ -452,13 +478,14 @@ static void find_free_file(char** filename)
 | 
			
		||||
static void usage(char* program_name)
 | 
			
		||||
{
 | 
			
		||||
    printf("%s: Parallel HTTP file download\n", program_name);
 | 
			
		||||
    printf("usage: %s [-n nb_threads] [-l speed_limit] [-o out_filename] [-u user_agent] [-q] [-h] url\n",
 | 
			
		||||
    printf("usage: %s [-n nb_threads] [-l speed_limit] [-o out_filename] [-u user_agent] [-m max_chunk_size[kKmMgG] ] [-q] [-h] url\n",
 | 
			
		||||
        program_name);
 | 
			
		||||
    printf("\t-n : Specify number of threads (default : %d)\n", DEFAULT_NB_THREADS);
 | 
			
		||||
    printf("\t-l : Download speed limit for all threads (not per thread)\n");
 | 
			
		||||
    printf("\t-o : Out filename, default is retrieved by GET request or '%s' if not found\n",
 | 
			
		||||
           DEFAULT_OUT_FILENAME);
 | 
			
		||||
    printf("\t-u : User agent, default is '%s'\n", DEFAULT_USER_AGENT);
 | 
			
		||||
    printf("\t-m : Max chunk size in bytes\n");
 | 
			
		||||
    printf("\t-q : Quiet mode\n");
 | 
			
		||||
    printf("\t-h : Display help\n");
 | 
			
		||||
}
 | 
			
		||||
@@ -467,14 +494,15 @@ int main(int argc, char** argv)
 | 
			
		||||
{
 | 
			
		||||
    pthread_t display_thread = 0;
 | 
			
		||||
    unsigned nb_threads = DEFAULT_NB_THREADS;
 | 
			
		||||
    char* user_agent = strdup(DEFAULT_USER_AGENT);
 | 
			
		||||
    char* user_agent = strdup(DEFAULT_USER_AGENT), *endptr;
 | 
			
		||||
    stats_t* stats = NULL;
 | 
			
		||||
    int ret = -1, i;
 | 
			
		||||
    stats_params_t stats_params;
 | 
			
		||||
    transfert_t* transferts = NULL;
 | 
			
		||||
    unsigned total_size, thread_size;
 | 
			
		||||
    unsigned start, end, max_speed = 0, quiet = 0;
 | 
			
		||||
    char* out_filename = NULL, *url = NULL;
 | 
			
		||||
    unsigned total_size, thread_size, multiplier=1;
 | 
			
		||||
    double displayed_size;
 | 
			
		||||
    unsigned start, end, max_speed = 0, quiet = 0, max_chunk_size = 0;
 | 
			
		||||
    char* out_filename = NULL, *url = NULL, c;
 | 
			
		||||
    char* suffix = "B";
 | 
			
		||||
    void* res;
 | 
			
		||||
    int opt;
 | 
			
		||||
@@ -484,7 +512,7 @@ int main(int argc, char** argv)
 | 
			
		||||
    int continuous_mode=0;
 | 
			
		||||
    int exists;
 | 
			
		||||
 | 
			
		||||
    while ((opt = getopt(argc, argv, "hn:l:o:u:q")) != -1) {
 | 
			
		||||
    while ((opt = getopt(argc, argv, "hn:l:o:u:qm:")) != -1) {
 | 
			
		||||
        switch (opt) {
 | 
			
		||||
        case 'n':
 | 
			
		||||
            nb_threads = atoi(optarg);
 | 
			
		||||
@@ -499,6 +527,39 @@ int main(int argc, char** argv)
 | 
			
		||||
        case 'l':
 | 
			
		||||
            max_speed = atoi(optarg);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'm':
 | 
			
		||||
            if (strlen(optarg) > 1)
 | 
			
		||||
            {
 | 
			
		||||
                c = optarg[strlen(optarg)-1];
 | 
			
		||||
                if (c < '0' || c > '9')
 | 
			
		||||
                {
 | 
			
		||||
                    switch(c)
 | 
			
		||||
                    {
 | 
			
		||||
                    case 'g':
 | 
			
		||||
                    case 'G':
 | 
			
		||||
                        multiplier *= 1024;
 | 
			
		||||
                    case 'm':
 | 
			
		||||
                    case 'M':
 | 
			
		||||
                        multiplier *= 1024;
 | 
			
		||||
                    case 'k':
 | 
			
		||||
                    case 'K':
 | 
			
		||||
                        multiplier *= 1024;
 | 
			
		||||
                        optarg[strlen(optarg)-1] = 0;
 | 
			
		||||
                        break;
 | 
			
		||||
                    default:
 | 
			
		||||
                        usage(argv[0]);
 | 
			
		||||
                        return 1;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            max_chunk_size = strtoul(optarg, &endptr, 0);
 | 
			
		||||
            if (*endptr)
 | 
			
		||||
            {
 | 
			
		||||
                usage(argv[0]);
 | 
			
		||||
                return 1;
 | 
			
		||||
            }
 | 
			
		||||
            max_chunk_size *= multiplier;
 | 
			
		||||
            break;
 | 
			
		||||
        case 'o':
 | 
			
		||||
            out_filename = strdup(optarg);
 | 
			
		||||
            break;
 | 
			
		||||
@@ -539,7 +600,29 @@ int main(int argc, char** argv)
 | 
			
		||||
        goto end;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        printf("Save in '%s'\n\n", out_filename);
 | 
			
		||||
    {
 | 
			
		||||
        displayed_size = (double)total_size;
 | 
			
		||||
        suffix = "B";
 | 
			
		||||
        if (displayed_size > (1024))
 | 
			
		||||
        {
 | 
			
		||||
            displayed_size /= 1024.0;
 | 
			
		||||
            suffix = "kB";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (displayed_size > (1024))
 | 
			
		||||
        {
 | 
			
		||||
            displayed_size /= 1024.0;
 | 
			
		||||
            suffix = "MB";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (displayed_size > (1024))
 | 
			
		||||
        {
 | 
			
		||||
            displayed_size /= 1024.0;
 | 
			
		||||
            suffix = "GB";
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        printf("Save in '%s' (%.2f%s)\n\n", out_filename, displayed_size, suffix);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stats = malloc(sizeof(*stats)*nb_threads);
 | 
			
		||||
    memset(stats, 0, sizeof(*stats)*nb_threads);
 | 
			
		||||
@@ -561,10 +644,16 @@ int main(int argc, char** argv)
 | 
			
		||||
            end = total_size;
 | 
			
		||||
 | 
			
		||||
        ret = configure_transfert(i, &transferts[i], url, out_filename,
 | 
			
		||||
                                  start, end, max_speed, user_agent, &exists);
 | 
			
		||||
                                  start, end, max_speed, user_agent,
 | 
			
		||||
                                  max_chunk_size, &exists);
 | 
			
		||||
        if (ret)
 | 
			
		||||
            goto end;
 | 
			
		||||
 | 
			
		||||
        transferts[i].stats[i].dltotal = transferts[i].already_downloaded +
 | 
			
		||||
            (end - start);
 | 
			
		||||
        transferts[i].stats[i].dlnow = transferts[i].already_downloaded;
 | 
			
		||||
        transferts[i].stats[i].dllast = 0;
 | 
			
		||||
 | 
			
		||||
        // First set continuous mode
 | 
			
		||||
        if (i == 0)
 | 
			
		||||
        {
 | 
			
		||||
@@ -583,7 +672,8 @@ int main(int argc, char** argv)
 | 
			
		||||
 | 
			
		||||
    // Check for last temporary file
 | 
			
		||||
    configure_transfert(i, &transferts[i], url, out_filename,
 | 
			
		||||
                        start, end, max_speed, user_agent, &exists);
 | 
			
		||||
                        start, end, max_speed, user_agent, max_chunk_size,
 | 
			
		||||
                        &exists);
 | 
			
		||||
    unlink(transferts[i].tmp_filename);
 | 
			
		||||
 | 
			
		||||
    if (exists)
 | 
			
		||||
@@ -665,7 +755,8 @@ end:
 | 
			
		||||
    if (transferts)
 | 
			
		||||
        free(transferts);
 | 
			
		||||
 | 
			
		||||
    printf("\n");
 | 
			
		||||
    if (!quiet)
 | 
			
		||||
        printf("\n");
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user