From bc7ab356db31c92553347c9643b817d4234b0d84 Mon Sep 17 00:00:00 2001 From: Matteo Paonessa Date: Sat, 17 Dec 2016 00:46:46 +0100 Subject: [PATCH] Args parsing --- .gitignore | 1 + README.md | 7 +- src/helper.c | 58 ++-- src/helper.h | 11 +- src/main.c | 23 +- src/tinydir.h | 804 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils.c | 77 ++++- src/utils.h | 4 + 8 files changed, 952 insertions(+), 33 deletions(-) create mode 100644 src/tinydir.h diff --git a/.gitignore b/.gitignore index 9621025..ce6994c 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ Thumbs.db .idea src_orig cmake-build-* +old_src \ No newline at end of file diff --git a/README.md b/README.md index 50417a4..2454849 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ See INSTALL for more details. Losslessly compress ```image1.jpg```, located in the ```home``` directory, into a folder called ```output``` ``` -$ caesiumclt -l -o ~/output/ ~/image.jpg +$ caesiumclt -q 0 -o ~/output/ ~/image.jpg ``` Compress ```image1.jpg```, located in the ```home``` directory, into a folder called ```output``` with lossy compression and quality set to 80 @@ -35,12 +35,12 @@ $ caesiumclt -q 80 -o ~/output/ ~/image.jpg Losslessly compress ```image1.jpg```, located in the ```home``` directory, into a folder called ```output``` and keeps EXIF metadata ``` -$ caesiumclt -l -e -o ~/output/ ~/image.jpg +$ caesiumclt -q 0 -e -o ~/output/ ~/image.jpg ``` Losslessly compress ```Pictures``` folder and subfolders, located in the ```home``` directory, into a folder called ```output``` ``` -$ caesiumclt -l -R -o ~/output/ ~/Pictures +$ caesiumclt -q 0 -R -o ~/output/ ~/Pictures ``` ---------- @@ -57,6 +57,7 @@ $ caesiumclt -l -R -o ~/output/ ~/Pictures ---------- ###### CHANGELOG +* 0.10.0-beta - Switched to cmake and libcaesium * 0.9.1-beta - Initial development stage Check the [Commits](https://github.com/Lymphatus/CaesiumCLT/commits/master) for a detailed list of changes. diff --git a/src/helper.c b/src/helper.c index 4262daf..a2b261e 100644 --- a/src/helper.c +++ b/src/helper.c @@ -1,12 +1,13 @@ #include #include +#include #include "helper.h" #include "optparse.h" #include "utils.h" void initialize_jpeg_parameters(cs_image_pars *options) { - options->jpeg.quality = 65; + options->jpeg.quality = 0; options->jpeg.exif_copy = false; options->jpeg.dct_method = 2048; options->jpeg.width = 0; @@ -33,19 +34,18 @@ cs_image_pars initialize_parameters() return options; } -cs_image_pars parse_arguments(int argc, char **argv) +cclt_options parse_arguments(char **argv, cs_image_pars *options) { - struct optparse options; - //Initialize the default parameters - cs_image_pars result = initialize_parameters(); + struct optparse opts; + //Initialize application options + cclt_options result = {NULL, NULL, false, false, 0}; //Parse command line args - optparse_init(&options, argv); + optparse_init(&opts, argv); struct optparse_long longopts[] = { {"quality", 'q', OPTPARSE_REQUIRED}, {"exif", 'e', OPTPARSE_NONE}, {"output", 'o', OPTPARSE_REQUIRED}, - {"lossless", 'l', OPTPARSE_NONE}, {"recursive", 'R', OPTPARSE_NONE}, {"keep-structure", 'S', OPTPARSE_NONE}, {"version", 'v', OPTPARSE_NONE}, @@ -54,44 +54,58 @@ cs_image_pars parse_arguments(int argc, char **argv) }; int option; - while ((option = optparse_long(&options, longopts, NULL)) != -1) { + while ((option = optparse_long(&opts, longopts, NULL)) != -1) { switch (option) { case 'q': - result.jpeg.quality = atoi(options.optarg); + options->jpeg.quality = atoi(opts.optarg); break; case 'e': - result.jpeg.exif_copy = true; + options->jpeg.exif_copy = true; break; case 'o': - //TODO General args - break; - case 'l': - result.jpeg.quality = 0; + result.output_folder = malloc((strlen(opts.optarg) + 1) * sizeof(char)); + strncpy(result.output_folder, opts.optarg, strlen(opts.optarg) + 1); break; case 'R': - //TODO General args + result.recursive = true; break; case 'S': - //TODO General args + result.keep_structure = true; break; case 'v': - fprintf(stdout, - "%s-%d\n", APP_VERSION_STRING, BUILD); + fprintf(stdout, "%s-%d\n", APP_VERSION_STRING, BUILD); exit(EXIT_SUCCESS); case 'h': print_help(); break; case '?': default: - fprintf(stderr, "%s: %s\n", argv[0], options.errmsg); + fprintf(stderr, "%s: %s\n", argv[0], opts.errmsg); exit(EXIT_FAILURE); } } - /* Print remaining arguments. */ + //Remaining arguments char *arg; - while ((arg = optparse_arg(&options))) - printf("%s\n", arg); + bool files_flag = false, folders_flag = false; + while ((arg = optparse_arg(&opts))) { + //TODO Check if there's a folder and change behaviour accordingly + //Check if it's a directory and add its content + if (is_directory(arg)) { + //NOTE Scanning a folder with this function does not check if we are actually getting images + //The actual check is performed by the library + + } else { + result.input_files = realloc(result.input_files, (result.files_count + 1) * sizeof(char*)); + result.input_files[result.files_count] = malloc((strlen(arg) + 1) * sizeof(char)); + strncpy(result.input_files[result.files_count], arg, strlen(opts.optarg) + 1); + result.files_count++; + } + //If there're files and folders, we cannot keep the structure + //TODO Trigger a warning + result.keep_structure = !(files_flag && folders_flag); + } + return result; } diff --git a/src/helper.h b/src/helper.h index 3365b49..372b9fd 100644 --- a/src/helper.h +++ b/src/helper.h @@ -3,12 +3,21 @@ #include +typedef struct cclt_options { + char **input_files; + char *output_folder; + bool recursive; + bool keep_structure; + int files_count; +} cclt_options; + + void initialize_jpeg_parameters(cs_image_pars *options); void initialize_png_parameters(cs_image_pars *options); cs_image_pars initialize_parameters(); -cs_image_pars parse_arguments(int argc, char *argv[]); +cclt_options parse_arguments(char *argv[], cs_image_pars *options); #endif //CAESIUM_CLT_HELPER_H diff --git a/src/main.c b/src/main.c index 617f4d8..12de08e 100755 --- a/src/main.c +++ b/src/main.c @@ -2,19 +2,36 @@ #include #include #include +#include #include "utils.h" +#include "helper.h" int main(int argc, char* argv[]) { errno = 0; long execution_ms = 0; - //TODO Parse arguments + cs_image_pars compress_options; + cclt_options options; + //Initialize the default parameters + compress_options = initialize_parameters(); + options = parse_arguments(argv, &compress_options); //Start a timer before calling the compression clock_t start = clock(), diff; //TODO Compress here - //start(input_files, output_folder, options); + //start(input_files, output_folder, &options); + printf("%s\n", options.output_folder); + + for (int i = 0; i < options.files_count; i++) { + printf("%s\n", options.input_files[i]); + } + + scan_folder("/Users/lymphatus/Documents/Progetti/C/caesium-clt/samples"); + + //Cleanup the two memory allocated objects + free(options.output_folder); + free(options.input_files); //Get the difference diff = clock() - start; @@ -24,4 +41,6 @@ int main(int argc, char* argv[]) { fprintf(stdout, "Performed in %lum%lus%lums\n", execution_ms / 1000 / 60, execution_ms / 1000 % 60, execution_ms % 1000); + + exit(EXIT_SUCCESS); } \ No newline at end of file diff --git a/src/tinydir.h b/src/tinydir.h new file mode 100644 index 0000000..3bd0bd6 --- /dev/null +++ b/src/tinydir.h @@ -0,0 +1,804 @@ +/* +Copyright (c) 2013-2016, tinydir authors: +- Cong Xu +- Lautis Sun +- Baudouin Feildel +- Andargor +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef TINYDIR_H +#define TINYDIR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if ((defined _UNICODE) && !(defined UNICODE)) +#define UNICODE +#endif + +#if ((defined UNICODE) && !(defined _UNICODE)) +#define _UNICODE +#endif + +#include +#include +#include +#ifdef _MSC_VER +# define WIN32_LEAN_AND_MEAN +# include +# include +# pragma warning(push) +# pragma warning (disable : 4996) +#else +# include +# include +# include +# include +#endif +#ifdef __MINGW32__ +# include +#endif + + +/* types */ + +/* Windows UNICODE wide character support */ +#if defined _MSC_VER || defined __MINGW32__ +#define _tinydir_char_t TCHAR +#define TINYDIR_STRING(s) _TEXT(s) +#define _tinydir_strlen _tcslen +#define _tinydir_strcpy _tcscpy +#define _tinydir_strcat _tcscat +#define _tinydir_strcmp _tcscmp +#define _tinydir_strrchr _tcsrchr +#define _tinydir_strncmp _tcsncmp +#else +#define _tinydir_char_t char +#define TINYDIR_STRING(s) s +#define _tinydir_strlen strlen +#define _tinydir_strcpy strcpy +#define _tinydir_strcat strcat +#define _tinydir_strcmp strcmp +#define _tinydir_strrchr strrchr +#define _tinydir_strncmp strncmp +#endif + +#if (defined _MSC_VER || defined __MINGW32__) +#include +#define _TINYDIR_PATH_MAX MAX_PATH +#elif defined __linux__ +#include +#define _TINYDIR_PATH_MAX PATH_MAX +#else +#define _TINYDIR_PATH_MAX 4096 +#endif + +#ifdef _MSC_VER +/* extra chars for the "\\*" mask */ +# define _TINYDIR_PATH_EXTRA 2 +#else +# define _TINYDIR_PATH_EXTRA 0 +#endif + +#define _TINYDIR_FILENAME_MAX 256 + +#if (defined _MSC_VER || defined __MINGW32__) +#define _TINYDIR_DRIVE_MAX 3 +#endif + +#ifdef _MSC_VER +# define _TINYDIR_FUNC static __inline +#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# define _TINYDIR_FUNC static __inline__ +#else +# define _TINYDIR_FUNC static inline +#endif + +/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */ +#ifdef TINYDIR_USE_READDIR_R + +/* readdir_r is a POSIX-only function, and may not be available under various + * environments/settings, e.g. MinGW. Use readdir fallback */ +#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\ + _POSIX_SOURCE +# define _TINYDIR_HAS_READDIR_R +#endif +#if _POSIX_C_SOURCE >= 200112L +# define _TINYDIR_HAS_FPATHCONF +# include +#endif +#if _BSD_SOURCE || _SVID_SOURCE || \ + (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) +# define _TINYDIR_HAS_DIRFD +# include +#endif +#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\ + defined _PC_NAME_MAX +# define _TINYDIR_USE_FPATHCONF +#endif +#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\ + !(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX) +# define _TINYDIR_USE_READDIR +#endif + +/* Use readdir by default */ +#else +# define _TINYDIR_USE_READDIR +#endif + +/* MINGW32 has two versions of dirent, ASCII and UNICODE*/ +#ifndef _MSC_VER +#if (defined __MINGW32__) && (defined _UNICODE) +#define _TINYDIR_DIR _WDIR +#define _tinydir_dirent _wdirent +#define _tinydir_opendir _wopendir +#define _tinydir_readdir _wreaddir +#define _tinydir_closedir _wclosedir +#else +#define _TINYDIR_DIR DIR +#define _tinydir_dirent dirent +#define _tinydir_opendir opendir +#define _tinydir_readdir readdir +#define _tinydir_closedir closedir +#endif +#endif + +/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */ +#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE) +#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE) +#else +#error "Either define both alloc and free or none of them!" +#endif + +#if !defined(_TINYDIR_MALLOC) +#define _TINYDIR_MALLOC(_size) malloc(_size) +#define _TINYDIR_FREE(_ptr) free(_ptr) +#endif /* !defined(_TINYDIR_MALLOC) */ + +typedef struct tinydir_file +{ + _tinydir_char_t path[_TINYDIR_PATH_MAX]; + _tinydir_char_t name[_TINYDIR_FILENAME_MAX]; + _tinydir_char_t *extension; + int is_dir; + int is_reg; + +#ifndef _MSC_VER +#ifdef __MINGW32__ + struct _stat _s; +#else + struct stat _s; +#endif +#endif +} tinydir_file; + +typedef struct tinydir_dir +{ + _tinydir_char_t path[_TINYDIR_PATH_MAX]; + int has_next; + size_t n_files; + + tinydir_file *_files; +#ifdef _MSC_VER + HANDLE _h; + WIN32_FIND_DATA _f; +#else + _TINYDIR_DIR *_d; + struct _tinydir_dirent *_e; +#ifndef _TINYDIR_USE_READDIR + struct _tinydir_dirent *_ep; +#endif +#endif +} tinydir_dir; + + +/* declarations */ + +_TINYDIR_FUNC +int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path); +_TINYDIR_FUNC +int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path); +_TINYDIR_FUNC +void tinydir_close(tinydir_dir *dir); + +_TINYDIR_FUNC +int tinydir_next(tinydir_dir *dir); +_TINYDIR_FUNC +int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file); +_TINYDIR_FUNC +int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i); +_TINYDIR_FUNC +int tinydir_open_subdir_n(tinydir_dir *dir, size_t i); + +_TINYDIR_FUNC +int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path); +_TINYDIR_FUNC +void _tinydir_get_ext(tinydir_file *file); +_TINYDIR_FUNC +int _tinydir_file_cmp(const void *a, const void *b); +#ifndef _MSC_VER +#ifndef _TINYDIR_USE_READDIR +_TINYDIR_FUNC +size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp); +#endif +#endif + + +/* definitions*/ + +_TINYDIR_FUNC +int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path) +{ +#ifndef _MSC_VER +#ifndef _TINYDIR_USE_READDIR + int error; + int size; /* using int size */ +#endif +#else + _tinydir_char_t path_buf[_TINYDIR_PATH_MAX]; +#endif + _tinydir_char_t *pathp; + + if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0) + { + errno = EINVAL; + return -1; + } + if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + + /* initialise dir */ + dir->_files = NULL; +#ifdef _MSC_VER + dir->_h = INVALID_HANDLE_VALUE; +#else + dir->_d = NULL; +#ifndef _TINYDIR_USE_READDIR + dir->_ep = NULL; +#endif +#endif + tinydir_close(dir); + + _tinydir_strcpy(dir->path, path); + /* Remove trailing slashes */ + pathp = &dir->path[_tinydir_strlen(dir->path) - 1]; + while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/'))) + { + *pathp = TINYDIR_STRING('\0'); + pathp++; + } +#ifdef _MSC_VER + _tinydir_strcpy(path_buf, dir->path); + _tinydir_strcat(path_buf, TINYDIR_STRING("\\*")); + dir->_h = FindFirstFile(path_buf, &dir->_f); + if (dir->_h == INVALID_HANDLE_VALUE) + { + errno = ENOENT; +#else + dir->_d = _tinydir_opendir(path); + if (dir->_d == NULL) + { +#endif + goto bail; + } + + /* read first file */ + dir->has_next = 1; +#ifndef _MSC_VER +#ifdef _TINYDIR_USE_READDIR + dir->_e = _tinydir_readdir(dir->_d); +#else + /* allocate dirent buffer for readdir_r */ + size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */ + if (size == -1) return -1; + dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size); + if (dir->_ep == NULL) return -1; + + error = readdir_r(dir->_d, dir->_ep, &dir->_e); + if (error != 0) return -1; +#endif + if (dir->_e == NULL) + { + dir->has_next = 0; + } +#endif + + return 0; + + bail: + tinydir_close(dir); + return -1; +} + +_TINYDIR_FUNC +int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path) +{ + /* Count the number of files first, to pre-allocate the files array */ + size_t n_files = 0; + if (tinydir_open(dir, path) == -1) + { + return -1; + } + while (dir->has_next) + { + n_files++; + if (tinydir_next(dir) == -1) + { + goto bail; + } + } + tinydir_close(dir); + + if (tinydir_open(dir, path) == -1) + { + return -1; + } + + dir->n_files = 0; + dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files); + if (dir->_files == NULL) + { + goto bail; + } + while (dir->has_next) + { + tinydir_file *p_file; + dir->n_files++; + + p_file = &dir->_files[dir->n_files - 1]; + if (tinydir_readfile(dir, p_file) == -1) + { + goto bail; + } + + if (tinydir_next(dir) == -1) + { + goto bail; + } + + /* Just in case the number of files has changed between the first and + second reads, terminate without writing into unallocated memory */ + if (dir->n_files == n_files) + { + break; + } + } + + qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp); + + return 0; + + bail: + tinydir_close(dir); + return -1; +} + +_TINYDIR_FUNC +void tinydir_close(tinydir_dir *dir) +{ + if (dir == NULL) + { + return; + } + + memset(dir->path, 0, sizeof(dir->path)); + dir->has_next = 0; + dir->n_files = 0; + _TINYDIR_FREE(dir->_files); + dir->_files = NULL; +#ifdef _MSC_VER + if (dir->_h != INVALID_HANDLE_VALUE) + { + FindClose(dir->_h); + } + dir->_h = INVALID_HANDLE_VALUE; +#else + if (dir->_d) + { + _tinydir_closedir(dir->_d); + } + dir->_d = NULL; + dir->_e = NULL; +#ifndef _TINYDIR_USE_READDIR + _TINYDIR_FREE(dir->_ep); + dir->_ep = NULL; +#endif +#endif +} + +_TINYDIR_FUNC +int tinydir_next(tinydir_dir *dir) +{ + if (dir == NULL) + { + errno = EINVAL; + return -1; + } + if (!dir->has_next) + { + errno = ENOENT; + return -1; + } + +#ifdef _MSC_VER + if (FindNextFile(dir->_h, &dir->_f) == 0) +#else +#ifdef _TINYDIR_USE_READDIR + dir->_e = _tinydir_readdir(dir->_d); +#else + if (dir->_ep == NULL) + { + return -1; + } + if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0) + { + return -1; + } +#endif + if (dir->_e == NULL) +#endif + { + dir->has_next = 0; +#ifdef _MSC_VER + if (GetLastError() != ERROR_SUCCESS && + GetLastError() != ERROR_NO_MORE_FILES) + { + tinydir_close(dir); + errno = EIO; + return -1; + } +#endif + } + + return 0; +} + +_TINYDIR_FUNC +int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file) +{ + if (dir == NULL || file == NULL) + { + errno = EINVAL; + return -1; + } +#ifdef _MSC_VER + if (dir->_h == INVALID_HANDLE_VALUE) +#else + if (dir->_e == NULL) +#endif + { + errno = ENOENT; + return -1; + } + if (_tinydir_strlen(dir->path) + + _tinydir_strlen( +#ifdef _MSC_VER + dir->_f.cFileName +#else + dir->_e->d_name +#endif + ) + 1 + _TINYDIR_PATH_EXTRA >= + _TINYDIR_PATH_MAX) + { + /* the path for the file will be too long */ + errno = ENAMETOOLONG; + return -1; + } + if (_tinydir_strlen( +#ifdef _MSC_VER + dir->_f.cFileName +#else + dir->_e->d_name +#endif + ) >= _TINYDIR_FILENAME_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + + _tinydir_strcpy(file->path, dir->path); + _tinydir_strcat(file->path, TINYDIR_STRING("/")); + _tinydir_strcpy(file->name, + #ifdef _MSC_VER + dir->_f.cFileName +#else + dir->_e->d_name +#endif + ); + _tinydir_strcat(file->path, file->name); +#ifndef _MSC_VER +#ifdef __MINGW32__ + if (_tstat( +#else + if (stat( +#endif + file->path, &file->_s) == -1) + { + return -1; + } +#endif + _tinydir_get_ext(file); + + file->is_dir = +#ifdef _MSC_VER + !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); +#else + S_ISDIR(file->_s.st_mode); +#endif + file->is_reg = +#ifdef _MSC_VER + !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || + ( + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && +#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) && +#endif +#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) && +#endif + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && + !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY)); +#else + S_ISREG(file->_s.st_mode); +#endif + + return 0; +} + +_TINYDIR_FUNC +int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i) +{ + if (dir == NULL || file == NULL) + { + errno = EINVAL; + return -1; + } + if (i >= dir->n_files) + { + errno = ENOENT; + return -1; + } + + memcpy(file, &dir->_files[i], sizeof(tinydir_file)); + _tinydir_get_ext(file); + + return 0; +} + +_TINYDIR_FUNC +int tinydir_open_subdir_n(tinydir_dir *dir, size_t i) +{ + _tinydir_char_t path[_TINYDIR_PATH_MAX]; + if (dir == NULL) + { + errno = EINVAL; + return -1; + } + if (i >= dir->n_files || !dir->_files[i].is_dir) + { + errno = ENOENT; + return -1; + } + + _tinydir_strcpy(path, dir->_files[i].path); + tinydir_close(dir); + if (tinydir_open_sorted(dir, path) == -1) + { + return -1; + } + + return 0; +} + +/* Open a single file given its path */ +_TINYDIR_FUNC +int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path) +{ + tinydir_dir dir; + int result = 0; + int found = 0; + _tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX]; + _tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX]; + _tinydir_char_t *dir_name; + _tinydir_char_t *base_name; +#if (defined _MSC_VER || defined __MINGW32__) + _tinydir_char_t drive_buf[_TINYDIR_DRIVE_MAX]; + _tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX]; +#endif + + if (file == NULL || path == NULL || _tinydir_strlen(path) == 0) + { + errno = EINVAL; + return -1; + } + if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) + { + errno = ENAMETOOLONG; + return -1; + } + + /* Get the parent path */ +#if (defined _MSC_VER || defined __MINGW32__) + #if ((defined _MSC_VER) && (_MSC_VER >= 1400)) + _tsplitpath_s( + path, + drive_buf, _TINYDIR_DRIVE_MAX, + dir_name_buf, _TINYDIR_FILENAME_MAX, + file_name_buf, _TINYDIR_FILENAME_MAX, + ext_buf, _TINYDIR_FILENAME_MAX); +#else + _tsplitpath( + path, + drive_buf, + dir_name_buf, + file_name_buf, + ext_buf); +#endif + +/* _splitpath_s not work fine with only filename and widechar support */ +#ifdef _UNICODE + if (drive_buf[0] == L'\xFEFE') + drive_buf[0] = '\0'; + if (dir_name_buf[0] == L'\xFEFE') + dir_name_buf[0] = '\0'; +#endif + + if (errno) + { + errno = EINVAL; + return -1; + } + /* Emulate the behavior of dirname by returning "." for dir name if it's + empty */ + if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0') + { + _tinydir_strcpy(dir_name_buf, TINYDIR_STRING(".")); + } + /* Concatenate the drive letter and dir name to form full dir name */ + _tinydir_strcat(drive_buf, dir_name_buf); + dir_name = drive_buf; + /* Concatenate the file name and extension to form base name */ + _tinydir_strcat(file_name_buf, ext_buf); + base_name = file_name_buf; +#else + _tinydir_strcpy(dir_name_buf, path); + dir_name = dirname(dir_name_buf); + _tinydir_strcpy(file_name_buf, path); + base_name =basename(file_name_buf); +#endif + + /* Open the parent directory */ + if (tinydir_open(&dir, dir_name) == -1) + { + return -1; + } + + /* Read through the parent directory and look for the file */ + while (dir.has_next) + { + if (tinydir_readfile(&dir, file) == -1) + { + result = -1; + goto bail; + } + if (_tinydir_strcmp(file->name, base_name) == 0) + { + /* File found */ + found = 1; + break; + } + tinydir_next(&dir); + } + if (!found) + { + result = -1; + errno = ENOENT; + } + + bail: + tinydir_close(&dir); + return result; +} + +_TINYDIR_FUNC +void _tinydir_get_ext(tinydir_file *file) +{ + _tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.')); + if (period == NULL) + { + file->extension = &(file->name[_tinydir_strlen(file->name)]); + } + else + { + file->extension = period + 1; + } +} + +_TINYDIR_FUNC +int _tinydir_file_cmp(const void *a, const void *b) +{ + const tinydir_file *fa = (const tinydir_file *)a; + const tinydir_file *fb = (const tinydir_file *)b; + if (fa->is_dir != fb->is_dir) + { + return -(fa->is_dir - fb->is_dir); + } + return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX); +} + +#ifndef _MSC_VER +#ifndef _TINYDIR_USE_READDIR +/* +The following authored by Ben Hutchings +from https://womble.decadent.org.uk/readdir_r-advisory.html +*/ +/* Calculate the required buffer size (in bytes) for directory * +* entries read from the given directory handle. Return -1 if this * +* this cannot be done. * +* * +* This code does not trust values of NAME_MAX that are less than * +* 255, since some systems (including at least HP-UX) incorrectly * +* define it to be a smaller value. */ +_TINYDIR_FUNC +size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp) +{ + long name_max; + size_t name_end; + /* parameter may be unused */ + (void)dirp; + +#if defined _TINYDIR_USE_FPATHCONF + name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX); + if (name_max == -1) +#if defined(NAME_MAX) + name_max = (NAME_MAX > 255) ? NAME_MAX : 255; +#else + return (size_t)(-1); +#endif +#elif defined(NAME_MAX) + name_max = (NAME_MAX > 255) ? NAME_MAX : 255; +#else +#error "buffer size for readdir_r cannot be determined" +#endif + name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1; + return (name_end > sizeof(struct _tinydir_dirent) ? + name_end : sizeof(struct _tinydir_dirent)); +} +#endif +#endif + +#ifdef __cplusplus +} +#endif + +# if defined (_MSC_VER) +# pragma warning(pop) +# endif + +#endif \ No newline at end of file diff --git a/src/utils.c b/src/utils.c index c46b415..fc81616 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,7 +1,11 @@ #include #include -#include +#include +#include +#include #include "utils.h" +#include "tinydir.h" + void print_help() { @@ -11,14 +15,77 @@ void print_help() "Compress your pictures up to 90%% without visible quality loss.\n\n" "Options:\n" - "\t-q, --quality\t\t\tset output file quality between [1-100], JPEG only\n" + "\t-q, --quality\t\t\tset output file quality between [0-100], 0 for optimization\n" "\t-e, --exif\t\t\t\tkeeps EXIF info during compression\n" "\t-o, --output\t\t\toutput folder\n" - "\t-l, --lossless\t\t\tuse lossless optimization\n" "\t-R, --recursive\t\t\tif input is a folder, scan subfolders too\n" //TODO Remove this warning - "\t-S, --keep-structure\tkeep the folder structure [Not active yet]\n" + "\t-S, --keep-structure\tkeep the folder structure [Not active yet], use with -R\n" "\t-h, --help\t\t\t\tdisplay this help and exit\n" "\t-v, --version\t\t\toutput version information and exit\n\n"); exit(EXIT_SUCCESS); -} \ No newline at end of file +} + +int is_directory(const char* path) +{ + struct stat sb; + + return ((stat(path, &sb) && S_ISDIR(sb.st_mode))); + +} + +int scan_folder(const char *directory) +{ + //TODO Not recursive at all + int n = 0; + tinydir_dir dir; + tinydir_open(&dir, directory); + + while (dir.has_next) + { + tinydir_file file; + tinydir_readfile(&dir, &file); + + if (file.is_dir) { + if (strcmp(file.name, ".") != 0 && strcmp(file.name, "..") != 0) { + printf("%s/", file.name); + char real[PATH_MAX]; + realpath(file.name, real); + scan_folder(real); + } + } else { + printf("%s\n", file.name); + } + + tinydir_next(&dir); + n++; + } + + tinydir_close(&dir); + return 0; +} + +/* + * int n = 0; + tinydir_dir dir; + tinydir_open(&dir, directory); + + while (dir.has_next) { + tinydir_file file; + tinydir_readfile(&dir, &file); + + printf("%s", file.name); + if (file.is_dir && (file.name != "." && file.name != "..")) { + scan_folder(file.name); + printf("/"); + } else { + tinydir_next(&dir); + n++; + } + printf("\n"); + } + + tinydir_close(&dir); + return 0; + */ + diff --git a/src/utils.h b/src/utils.h index b6b5b9a..3cdc9c4 100644 --- a/src/utils.h +++ b/src/utils.h @@ -11,4 +11,8 @@ void print_help(); +int is_directory(const char* path); + +int scan_folder(const char* directory); + #endif //CAESIUM_CLT_UTILS_H