Version 0.1.
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Tue, 1 Dec 2009 20:07:45 +0000 (21:07 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Tue, 1 Dec 2009 20:07:45 +0000 (21:07 +0100)
Makefile [new file with mode: 0644]
ccp.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..ed17d66
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,23 @@
+
+PREFIX=$(HOME)
+BINDIR=$(PREFIX)/bin
+
+all: ccp cmv
+
+cmv: ccp
+       ln -s ccp cmv
+
+ccp: ccp.o
+       gcc -o $@ $^
+
+ccp.o: ccp.c
+       gcc -Wall -c -o $@ $^
+
+install: all
+       cp ccp "$(BINDIR)/ccp"
+       rm -f "$(BINDIR)/cmv"
+       ln -s ccp "$(BINDIR)/cmv"
+
+clean:
+       rm -f ccp cmv
+       rm -f ccp.o
diff --git a/ccp.c b/ccp.c
new file mode 100644 (file)
index 0000000..6a40186
--- /dev/null
+++ b/ccp.c
@@ -0,0 +1,300 @@
+/**
+ * ccp.c - a cp replacement with progress bar
+ *
+ * @version $Id: ccp.c 769 2008-04-26 10:53:11Z bombe $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/timeb.h>
+#include <time.h>
+
+#define false 0
+#define true !false
+
+int redrawProgressBar = false;
+
+void handleWindowResize(int signalNumber) {
+       signal(signalNumber, SIG_IGN);
+
+       redrawProgressBar = true;
+
+       signal(signalNumber, handleWindowResize);
+}
+
+int getColumns() {
+       struct winsize terminalSize;
+       int error;
+
+       error = ioctl(1, TIOCGWINSZ, &terminalSize);
+       
+       if (!error) {
+               return terminalSize.ws_col;
+       }
+       return 80;
+}
+
+char *extractFilename(char *pathName) {
+       char* result;
+
+       result = strrchr(pathName, '/');
+       if (result) {
+               return result + 1;
+       }
+       return pathName;
+}
+
+int scaleProgress(char* fileName, double progress) {
+       int columns;
+
+       columns = getColumns() - 3 - strlen(fileName);
+       if (columns < 2) {
+               columns = 2;
+       }
+
+       return (int) (columns * progress);
+}
+
+void printProgress(char* fileName, int currentProgress) {
+       char* shortFileName;
+       int totalColumns;
+       int columns;
+       int i;
+
+       shortFileName = fileName;
+       totalColumns = getColumns();
+       columns = totalColumns - 3 - strlen(fileName);
+
+       if (columns < 2) {
+               shortFileName = fileName + (strlen(fileName) - (totalColumns - 8));
+               columns = 2;
+       }
+
+       if (shortFileName != fileName) {
+               printf("...%s", shortFileName);
+       } else {
+               printf("%s", fileName);
+       }
+       printf(" [");
+       for (i = 0; i < columns; i++) {
+               printf((i < currentProgress) ? "*" : ".");
+       }
+       printf("]\r");
+       fflush(stdout);
+}
+
+int copyFileToFile(char* sourceFile, char* destFile) {
+       FILE* inputFile;
+       FILE* outputFile;
+       char* fileName;
+       long long fileSize;
+       size_t read;
+       size_t toWrite;
+       long long writtenTotal = 0;
+       size_t written;
+       int readSize;
+       int bufferSize;
+       void* buffer;
+       double progress;
+       int currentProgress = 0;
+       int lastProgress = -1;
+       struct timeb startTime, endTime;
+       long startTimeMillis, endTimeMillis, spent;
+
+       inputFile = fopen(sourceFile, "rb");
+       if (!inputFile) {
+               fprintf(stderr, "can not open \"%s\" for reading!\n", sourceFile);
+               return false;
+       }
+
+       outputFile = fopen(destFile, "wb");
+       if (!outputFile) {
+               fprintf(stderr, "can not open \"%s\" for writing!\n", destFile);
+               fclose(inputFile);
+               return false;
+       }
+
+       fseek(inputFile, 0, SEEK_END);
+       fileSize = ftell(inputFile);
+       fseek(inputFile, 0, SEEK_SET);
+
+       fileName = extractFilename(sourceFile);
+
+       bufferSize = 1 << 20;
+       readSize = bufferSize;
+       buffer = (void*) malloc(bufferSize);
+
+       while (!feof(inputFile)) {
+               ftime(&startTime);
+               read = fread(buffer, 1, readSize, inputFile);
+               if (read) {
+                       toWrite = read;
+                       do {
+                               written = fwrite(buffer + (read - toWrite), 1, toWrite, outputFile);
+                               if (!written) {
+                                       if (ferror(outputFile)) {
+                                               fprintf(stderr, "\nerror writing to \"%s\"!\n", destFile);
+                                               fclose(inputFile);
+                                               fclose(outputFile);
+                                               return false;
+                                       }
+                               }
+                               toWrite -= written;
+                       } while (toWrite);
+                       ftime(&endTime);
+                       writtenTotal += written;
+                       progress = (double) writtenTotal / fileSize;
+                       currentProgress = scaleProgress(fileName, progress);
+                       if ((currentProgress != lastProgress) || (redrawProgressBar)) {
+                               printProgress(fileName, currentProgress);
+                               lastProgress = currentProgress;
+                               redrawProgressBar = false;
+                       }
+                       endTimeMillis = endTime.time * 1000 + endTime.millitm;
+                       startTimeMillis = startTime.time * 1000 + startTime.millitm;
+                       spent = endTimeMillis - startTimeMillis;
+                       if (spent >= 200) {
+                               if (readSize > 2047) {
+                                       readSize >>= 1;
+                               }
+                       } else if (spent <= 50) {
+                               if (readSize < (1 << 19)) {
+                                       readSize <<= 1;
+                               }
+                       }
+               } else {
+                       if (ferror(inputFile)) {
+                               fprintf(stderr, "\nerror reading from \"%s\"!\n", sourceFile);
+                               fclose(inputFile);
+                               fclose(outputFile);
+                               return false;
+                       }
+               }
+       }
+       printf("\n");
+       fflush(stdout);
+       fclose(inputFile);
+       fclose(outputFile);
+
+       return true;
+}
+
+int copyFileToDirectory(char *sourceFile, char* destDirectory) {
+       char* fileName;
+       char* destFile;
+       int copyResult;
+
+       fileName = extractFilename(sourceFile);
+       destFile = (char*) calloc(strlen(destDirectory) + 1 + strlen(fileName) + 1, 1);
+       strcat(destFile, destDirectory);
+       strcat(destFile, "/");
+       strcat(destFile, fileName);
+
+       copyResult = copyFileToFile(sourceFile, destFile);
+
+       free(destFile);
+       return copyResult;
+}
+
+void printHelp() {
+       printf("Syntax: ccp SRC [SRC [...]] DEST\n\n");
+       printf("SRC must be a file. If DEST is a directory, an arbitrary amount of SRC\n");
+       printf("may be given. If DEST is an existing file or does not exist at all,\n");
+       printf("only one SRC is allowed.\n");
+}
+
+int isWritableFile(char *pathName) {
+       struct stat fileStat;
+       int statError;
+       FILE* testFd;
+
+       statError = stat(pathName, &fileStat);
+       if (statError == -1) {
+               if (errno == ENOENT) {
+                       testFd = fopen(pathName, "w");
+                       if (testFd) {
+                               fclose(testFd);
+                               return true;
+                       }
+               }
+               return false;
+       }
+       if (S_ISREG(fileStat.st_mode)) {
+               testFd = fopen(pathName, "ab+");
+               if (testFd) {
+                       fclose(testFd);
+                       return true;
+               }
+       }
+       return false;
+}
+
+int isDirectory(char *pathName) {
+       struct stat fileStat;
+       int statError;
+
+       statError = stat(pathName, &fileStat);
+       if (statError == -1) {
+               return false;
+       }
+       return S_ISDIR(fileStat.st_mode);
+}
+
+int checkForDirectoryOrNonExistingFile(char* pathName) {
+       return isDirectory(pathName) || isWritableFile(pathName);
+}
+
+int main(int argc, char** argv) {
+       char* lastArgument;
+       char* binaryName;
+       int destinationIsDirectory = false;
+       int fileIndex;
+       int moveFiles = false;
+
+       if (argc < 3) {
+               printHelp();
+               return 1;
+       }
+       lastArgument = argv[argc - 1];
+       if (!isDirectory(lastArgument)) {
+               if (isWritableFile(lastArgument)) {
+                       if (argc != 3) {
+                               printHelp();
+                               return 1;
+                       }
+               } else {
+                       fprintf(stderr, "\"%s\" is not a writable file.\n", lastArgument);
+                       return 2;
+               }
+       } else {
+               destinationIsDirectory = true;
+       }
+
+       binaryName = extractFilename(argv[0]);
+       if (!strcmp(binaryName, "cmv")) {
+               moveFiles = true;
+       }
+
+       signal(SIGWINCH, handleWindowResize);
+       for (fileIndex = 1; fileIndex < (argc - 1); fileIndex++) {
+               if (destinationIsDirectory) {
+                       if (copyFileToDirectory(argv[fileIndex], lastArgument) && moveFiles) {
+                               unlink(argv[fileIndex]);
+                       }
+               } else {
+                       if (copyFileToFile(argv[fileIndex], lastArgument) && moveFiles) {
+                               unlink(argv[fileIndex]);
+                       }
+               }
+       }
+
+       return 0;
+}