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