commit
75e2133ada
@ -0,0 +1 @@
|
||||
cpns
|
@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
all: clean cpns
|
||||
|
||||
clean:
|
||||
rm cpns
|
||||
|
||||
cpns:
|
||||
gcc main.c -Wall -o $@ -lm
|
@ -0,0 +1,281 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define __imdumb(one,two,three) strncpy(one,three,two)
|
||||
|
||||
int openOutputs(const char** ops, FILE*** fps, int* _cnt)
|
||||
{
|
||||
int ok =0;
|
||||
register int cnt = 0;
|
||||
|
||||
for(;ops[cnt];cnt++); (void)0;
|
||||
|
||||
*_cnt = cnt;
|
||||
if (cnt < 1) return -1;
|
||||
else {
|
||||
*fps = malloc(sizeof(FILE**)*cnt);
|
||||
for (int i=0;i<cnt;i++) {
|
||||
if(!((*fps)[i] = fopen(ops[i], "wb"))) {
|
||||
printf("Warning: Could not open `%s' for writing.\n", ops[i]);
|
||||
ok=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void closeOutputs(FILE** fps, int cnt)
|
||||
{
|
||||
for(int i=0;i<cnt;i++)
|
||||
if(fps[i]) fclose(fps[i]);
|
||||
free(fps);
|
||||
}
|
||||
|
||||
int ask(const char* thing)
|
||||
{
|
||||
printf(thing);
|
||||
char* line=NULL;
|
||||
size_t sz;
|
||||
if (getline(&line, &sz, stdin)==0) {
|
||||
int rt = (line[0] == 'y' || line[0] == 'Y');
|
||||
free(line);
|
||||
return rt;
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
#ifndef DEFAULT_BLOCKSIZE
|
||||
#define DEFAULT_BLOCKSIZE 1024
|
||||
#endif
|
||||
|
||||
int BLOCKSIZE = DEFAULT_BLOCKSIZE;
|
||||
|
||||
int copyBlock(FILE* op, FILE** fps, int sz)
|
||||
{
|
||||
static unsigned char *buf=NULL;
|
||||
|
||||
if(!buf) buf = malloc(BLOCKSIZE);
|
||||
|
||||
int rd = fread(buf, 1, BLOCKSIZE, op);
|
||||
|
||||
if(rd<1) return rd;
|
||||
|
||||
for(register int i=0;i<sz;i++)
|
||||
if(fps[i])
|
||||
fwrite(buf, 1, rd, fps[i]);
|
||||
|
||||
return rd;
|
||||
}
|
||||
|
||||
size_t sizeof_file(FILE* fp)
|
||||
{
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t ret = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define PROGRESS_SIZE 50
|
||||
|
||||
char* humanbytes(size_t sz)
|
||||
{
|
||||
static char buf[256];
|
||||
size_t b, lsz;
|
||||
size_t kb, mb,gb;
|
||||
|
||||
lsz = sz;
|
||||
memset(buf,0,256);
|
||||
|
||||
gb = sz / (1024*1024*1024);
|
||||
sz %= (1024*1024*1024);
|
||||
#define _D(v, t) (((double)v) / ((double)t))
|
||||
if(gb>0)
|
||||
{
|
||||
snprintf(buf, 255, "%.2f g", _D(lsz, (1024*2014*1024)));
|
||||
return buf;
|
||||
}
|
||||
|
||||
mb = sz / (1024+1024);
|
||||
sz %= (1024*1024);
|
||||
|
||||
if(mb>0)
|
||||
{
|
||||
snprintf(buf, 255, "%.2f m", _D(lsz, (1024*2014)));
|
||||
return buf;
|
||||
}
|
||||
|
||||
kb = sz / 1024;
|
||||
sz %= 1024;
|
||||
|
||||
if(kb>0)
|
||||
{
|
||||
snprintf(buf, 255, "%.2f k", _D(lsz, 1024));
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
b = sz;
|
||||
|
||||
snprintf(buf, 255, "%u b", (unsigned int)lsz);
|
||||
return buf;
|
||||
}
|
||||
|
||||
char* secstr(double tm)
|
||||
{
|
||||
static char buf[256];
|
||||
double sec = tm;
|
||||
int min,hr;
|
||||
min=hr=0;
|
||||
|
||||
while(sec>=60.0) { min +=1; sec-=6.0; }
|
||||
while(min>=60) { hr +=1; min -= 60; }
|
||||
|
||||
char* _buf=buf;
|
||||
int sz= 255;
|
||||
memset(_buf,0,256);
|
||||
|
||||
if(hr>0) {
|
||||
snprintf(_buf, sz, "%d h ", hr);
|
||||
sz -= strlen(_buf);
|
||||
_buf+=strlen(_buf);
|
||||
}
|
||||
if(min>0) {
|
||||
snprintf(_buf, sz, "%d m ", min);
|
||||
sz -= strlen(_buf);
|
||||
_buf+=strlen(_buf);
|
||||
}
|
||||
snprintf(_buf, sz, "%.2f s", sec);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char* remain(size_t small, size_t large, double bps)
|
||||
{
|
||||
static char buf[256];
|
||||
memset(buf,0,256);
|
||||
if(bps==0)
|
||||
__imdumb(buf, 255, "?");
|
||||
else {
|
||||
double vl = (large-small)/bps;
|
||||
__imdumb(buf, 255, secstr(vl));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct lastp {
|
||||
int fnum;
|
||||
int f2dp;
|
||||
int b2dp;
|
||||
char rem[256];
|
||||
};
|
||||
|
||||
int lastp_equalp(const struct lastp *v1, const struct lastp *v2) {
|
||||
return memcmp(v1, v2, sizeof(struct lastp)) == 0;
|
||||
}
|
||||
|
||||
void progress(size_t small, size_t large, size_t inc, time_t start, time_t elapsed)
|
||||
{
|
||||
static char* largesz = NULL;
|
||||
static char befores[256];
|
||||
|
||||
static struct lastp *lastvls = NULL;
|
||||
struct lastp thisvls;
|
||||
|
||||
if(!largesz)
|
||||
largesz = strdup(humanbytes(large));
|
||||
|
||||
double frac = ((double)small)/((double)large);
|
||||
double pct = (long)(frac*PROGRESS_SIZE);
|
||||
|
||||
double before = ((double)small)/((double)(elapsed-start));
|
||||
if(lastvls == NULL) {
|
||||
lastvls = malloc(sizeof(struct lastp));
|
||||
memset(lastvls, 0, sizeof(struct lastp));
|
||||
} else {
|
||||
memset(&thisvls, 0, sizeof(struct lastp));
|
||||
thisvls.fnum = (int) (frac*PROGRESS_SIZE);
|
||||
thisvls.f2dp = (int)round(frac*100.00 *100.00);
|
||||
thisvls.b2dp = (int)round(before*100.00);
|
||||
__imdumb(thisvls.rem, 255, remain(small,large,before));
|
||||
if (lastp_equalp(&thisvls, lastvls))
|
||||
return;
|
||||
}
|
||||
memset(befores, 0, 256);
|
||||
__imdumb(befores, 255, humanbytes((size_t)before));
|
||||
//printf("%c[2K", 27);
|
||||
printf("\r[");
|
||||
for(register int i=0;i<PROGRESS_SIZE;i++)
|
||||
printf("%c", (i<pct?'#':' '));
|
||||
printf("]: %.2f (%s / %s, (%s/s, ~%s left.) ", frac*100.0, humanbytes(small), largesz, befores, remain(small, large, before));
|
||||
|
||||
*lastvls = thisvls;
|
||||
}
|
||||
|
||||
void flag(const char* inp)
|
||||
{
|
||||
if(!*inp) return;
|
||||
switch(*inp) {
|
||||
case 'l':
|
||||
BLOCKSIZE += DEFAULT_BLOCKSIZE; break;
|
||||
case 's':
|
||||
BLOCKSIZE /= 2;
|
||||
if(BLOCKSIZE < 1) BLOCKSIZE = 1; break;
|
||||
default:
|
||||
printf("Warning: Unknown flag `%c'\n", *inp);
|
||||
break;
|
||||
}
|
||||
flag(inp+1);
|
||||
}
|
||||
|
||||
int main(int argc,const char** argv)
|
||||
{
|
||||
const char* input = argv[1];
|
||||
const char** output = argv+2;
|
||||
int rv=1;
|
||||
|
||||
redo:
|
||||
if (input == NULL || output[0]==NULL) {
|
||||
printf("Usage: %s <input> <outputs...>\n", argv[0]);
|
||||
} else {
|
||||
if(output[0][0] == '-')
|
||||
{
|
||||
flag(output[0]+1);
|
||||
output+=1;
|
||||
goto redo;
|
||||
}
|
||||
FILE* finput = fopen(input, "rb");
|
||||
if(!input) printf("Error: could not open `%s' for reading.\n", input);
|
||||
else {
|
||||
size_t input_sz = sizeof_file(finput);
|
||||
FILE** foutput;
|
||||
int ok, cnt;
|
||||
if((ok = openOutputs(output, &foutput, &cnt))>=0) {
|
||||
if(ok==1&& !ask("\nOne or more outputs failed to open, continue? (y/N) "))
|
||||
printf("Error: aborted\n");
|
||||
else {
|
||||
printf("Will copy %s to %d files with a blocksize of %d\n", humanbytes(input_sz), cnt, BLOCKSIZE);
|
||||
time_t start = time(NULL);
|
||||
int rd;
|
||||
size_t read=0;
|
||||
while( (rd=copyBlock(finput, foutput, cnt))>0)
|
||||
{
|
||||
read+=rd;
|
||||
progress(read, input_sz, rd,start, time(NULL));
|
||||
}
|
||||
time_t end = time(NULL);
|
||||
|
||||
char* dDone = strdup(humanbytes(read));
|
||||
printf("\n\nCopied %s to %d files in %s. (~%s /s)\n", dDone, cnt, secstr(end-start), humanbytes(((double)read)/((double)(end-start))));
|
||||
free(dDone);
|
||||
rv = 0;
|
||||
}
|
||||
closeOutputs(foutput, cnt);
|
||||
} else printf("Error: no output files could be opened\n");
|
||||
fclose(finput);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
Loading…
Reference in new issue