commit
ce0f68f790
|
@ -10,6 +10,163 @@ Thumbs.db
|
|||
.Spotlight-V100
|
||||
.Trashes
|
||||
|
||||
.idea
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.xml
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# CMake
|
||||
cmake-build-*
|
||||
build
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
### macOS template
|
||||
# General
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.TemporaryItems
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
### Linux template
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
### Windows template
|
||||
# Windows thumbnail cache files
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
### C template
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
|
@ -0,0 +1 @@
|
|||
caesiumclt
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
|
@ -0,0 +1,29 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<Objective-C-extensions>
|
||||
<file>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
||||
</file>
|
||||
<class>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
||||
</class>
|
||||
<extensions>
|
||||
<pair source="cpp" header="h" fileNamingConvention="NONE" />
|
||||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
||||
</extensions>
|
||||
</Objective-C-extensions>
|
||||
</code_scheme>
|
||||
</component>
|
|
@ -0,0 +1,125 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="ClangTidyInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="DeprecatedAPI" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="DuplicateSwitchCase" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="EndlessLoop" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="EqualityInConditionalOperator" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="FormatSpecifiers" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="FunctionImplicitDeclarationInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="HidesUpperScope" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="HidingNonVirtualFunction" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ImplicitIntegerAndEnumConversion" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ImplicitPointerAndIntegerConversion" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="IncompatibleEnums" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="IncompatibleInitializers" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="IncompatiblePointers" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="InfiniteRecursion" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="KRUnspecifiedParameters" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="LocalValueEscapesScope" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="MissingReturn" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="MissingSwitchCase" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="NotImplementedFunctions" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="NotInitializedVariable" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="NotSuperclass" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="OCDFAInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="OCLoopDoesntUseConditionVariableInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="OCSimplifyInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="OCUnusedGlobalDeclarationInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="OCUnusedMacroInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="OCUnusedStructInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="OCUnusedTemplateParameterInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="RedundantCast" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ResourceNotFoundInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SignednessMismatch" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnreachableCode" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnusedExpressionResult" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnusedImportStatement" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnusedLocalVariable" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnusedLocalization" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnusedParameter" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="UnusedValue" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="ValueMayNotFitIntoReceiver" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<scope name="Inspection" level="WARNING" enabled="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
<component name="CidrRootsConfiguration">
|
||||
<sourceRoots>
|
||||
<file path="$PROJECT_DIR$/src" />
|
||||
</sourceRoots>
|
||||
<excludeRoots>
|
||||
<file path="$PROJECT_DIR$/cmake-build-debug/CMakeFiles" />
|
||||
</excludeRoots>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/caesium-clt.iml" filepath="$PROJECT_DIR$/.idea/caesium-clt.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,3 @@
|
|||
<component name="DependencyValidationManager">
|
||||
<scope name="Inspection" pattern="!file:src/optparse.c&&!file:src/optparse.h&&!file:src/tinydir.h&&!file:.gitignore" />
|
||||
</component>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -3,8 +3,8 @@ project(caesiumclt)
|
|||
|
||||
# The version number.
|
||||
set(VERSION_MAJOR 0)
|
||||
set(VERSION_MINOR 10)
|
||||
set(VERSION_PATCH 2)
|
||||
set(VERSION_MINOR 11)
|
||||
set(VERSION_PATCH 0)
|
||||
|
||||
configure_file(
|
||||
"src/config.h.in"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
## Caesium CommandLineTools
|
||||
##### caesium-clt - v0.10.2-beta (build 20170318) - Copyright © Matteo Paonessa, 2017. All Rights Reserved.
|
||||
##### caesium-clt - v0.11.0-beta (build 20171109) - Copyright © Matteo Paonessa, 2017. All Rights Reserved.
|
||||
[](https://travis-ci.org/Lymphatus/caesium-clt)
|
||||
----------
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
|||
----------
|
||||
|
||||
###### TESTED PLATFORMS
|
||||
* Mac OS X Sierra (v10.12.3)
|
||||
* Mac OS X High Sierra (v10.13.1)
|
||||
* Ubuntu 16.04
|
||||
* Windows 10
|
||||
|
||||
|
@ -60,6 +60,7 @@ $ caesiumclt -q 0 -RS -o ~/output/ ~/Pictures
|
|||
----------
|
||||
|
||||
###### CHANGELOG
|
||||
* 0.11.0-beta - Fixing paths issues and dry-run option
|
||||
* 0.10.2-beta - Bugfixes & full Windows support
|
||||
* 0.10.1-beta - All features are available
|
||||
* 0.10.0-beta - Switched to cmake build system and libcaesium
|
||||
|
|
|
@ -39,9 +39,9 @@ const char *get_error_message(int code)
|
|||
case 9:
|
||||
return "Input files provided. Cannot mix them with a folder.";
|
||||
case 10:
|
||||
return "-R is useless on files.";
|
||||
return "-R has no effects on files.";
|
||||
case 11:
|
||||
return "-S is useless without -R.";
|
||||
return "-S has no effect without -R.";
|
||||
case 12:
|
||||
return "Cannot set output folder inside the input one";
|
||||
|
||||
|
|
143
src/helper.c
143
src/helper.c
|
@ -1,6 +1,11 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
#include "helper.h"
|
||||
#include "optparse.h"
|
||||
#include "utils.h"
|
||||
|
@ -11,7 +16,7 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
|||
{
|
||||
struct optparse opts;
|
||||
//Initialize application options
|
||||
cclt_options parameters = {NULL, NULL, false, false, 0, 0, 0};
|
||||
cclt_options parameters = {NULL, "", "", false, false, 0, 0, 0, false};
|
||||
|
||||
//Parse command line args
|
||||
optparse_init(&opts, argv);
|
||||
|
@ -21,33 +26,36 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
|||
{"output", 'o', OPTPARSE_REQUIRED},
|
||||
{"recursive", 'R', OPTPARSE_NONE},
|
||||
{"keep-structure", 'S', OPTPARSE_NONE},
|
||||
{"dry-run", 'd', OPTPARSE_NONE},
|
||||
{"version", 'v', OPTPARSE_NONE},
|
||||
{"help", 'h', OPTPARSE_NONE},
|
||||
{0}
|
||||
};
|
||||
int option;
|
||||
|
||||
int option;
|
||||
while ((option = optparse_long(&opts, longopts, NULL)) != -1) {
|
||||
switch (option) {
|
||||
case 'q':
|
||||
options->jpeg.quality = atoi(opts.optarg);
|
||||
options->jpeg.quality = (int) strtol(opts.optarg, (char **) NULL, 10);;
|
||||
if (options->jpeg.quality < 0 || options->jpeg.quality > 100) {
|
||||
display_error(ERROR, 1);
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
options->jpeg.exif_copy = true;
|
||||
break;
|
||||
case 'o':
|
||||
if (opts.optarg[strlen(opts.optarg) - 1] == '/' || opts.optarg[strlen(opts.optarg) - 1] == '\\') {
|
||||
parameters.output_folder = malloc((strlen(opts.optarg) + 1) * sizeof(char));
|
||||
if (opts.optarg[0] == '~') {
|
||||
snprintf(parameters.output_folder, strlen(opts.optarg) + 1, "%s", opts.optarg);
|
||||
} else {
|
||||
parameters.output_folder = malloc((strlen(opts.optarg) + 2) * sizeof(char));
|
||||
realpath(opts.optarg, parameters.output_folder);
|
||||
}
|
||||
if (parameters.output_folder[strlen(opts.optarg) - 1] != '/' &&
|
||||
parameters.output_folder[strlen(opts.optarg) - 1] != '\\') {
|
||||
#ifdef _WIN32
|
||||
snprintf(parameters.output_folder, strlen(opts.optarg) + 2, "%s\\", opts.optarg);
|
||||
snprintf(parameters.output_folder, strlen(parameters.output_folder) + 2, "%s\\", parameters.output_folder);
|
||||
#else
|
||||
snprintf(parameters.output_folder, strlen(opts.optarg) + 2, "%s/", opts.optarg);
|
||||
snprintf(parameters.output_folder, strlen(parameters.output_folder) + 2, "%s/",
|
||||
parameters.output_folder);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
@ -57,6 +65,9 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
|||
case 'S':
|
||||
parameters.keep_structure = true;
|
||||
break;
|
||||
case 'd':
|
||||
parameters.dry_run = true;
|
||||
break;
|
||||
case 'v':
|
||||
fprintf(stdout, "%d.%d.%d\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -69,22 +80,46 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
|||
display_error(ERROR, 2);
|
||||
}
|
||||
}
|
||||
|
||||
//Remaining arguments
|
||||
char *arg;
|
||||
bool files_flag = false, folders_flag = false;
|
||||
char resolved_path[MAX_PATH_SIZE];
|
||||
while ((arg = optparse_arg(&opts))) {
|
||||
if (folders_flag) {
|
||||
display_error(WARNING, 8);
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
//Check if it's a directory and add its content
|
||||
if (is_directory(arg)) {
|
||||
if (arg[0] == '~') {
|
||||
if (arg[strlen(arg) - 1] == '/' || arg[strlen(arg) - 1] == '\\') {
|
||||
snprintf(resolved_path, strlen(arg), "%s", arg);
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
snprintf(resolved_path, strlen(arg) + 1, "%s\\", arg);
|
||||
#else
|
||||
snprintf(resolved_path, strlen(arg) + 1, "%s/", arg);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
realpath(arg, resolved_path);
|
||||
}
|
||||
if (is_directory(resolved_path)) {
|
||||
if (!files_flag) {
|
||||
folders_flag = true;
|
||||
parameters.input_folder = strdup(arg);
|
||||
|
||||
if (resolved_path[strlen(resolved_path) - 1] != '/' && resolved_path[strlen(resolved_path) - 1] != '\\') {
|
||||
#ifdef _WIN32
|
||||
resolved_path[strlen(resolved_path)] = '\\';
|
||||
#else
|
||||
resolved_path[strlen(resolved_path)] = '/';
|
||||
#endif
|
||||
resolved_path[strlen(resolved_path)] = '\0';
|
||||
}
|
||||
|
||||
snprintf(parameters.input_folder, strlen(resolved_path) + 1, "%s", resolved_path);
|
||||
int count = 0;
|
||||
count = scan_folder(arg, ¶meters, parameters.recursive);
|
||||
count = scan_folder(resolved_path, ¶meters, parameters.recursive);
|
||||
if (count == 0) {
|
||||
display_error(WARNING, 3);
|
||||
}
|
||||
|
@ -93,7 +128,6 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
|||
}
|
||||
} else {
|
||||
files_flag = true;
|
||||
parameters.input_folder = NULL;
|
||||
parameters.input_files = realloc(parameters.input_files, (parameters.files_count + 1) * sizeof(char *));
|
||||
parameters.input_files[parameters.files_count] = malloc((strlen(arg) + 1) * sizeof(char));
|
||||
snprintf(parameters.input_files[parameters.files_count], strlen(arg) + 1, "%s", arg);
|
||||
|
@ -102,8 +136,12 @@ cclt_options parse_arguments(char **argv, cs_image_pars *options)
|
|||
}
|
||||
|
||||
//Check if the output folder is a subfolder of the input to avoid infinite loops
|
||||
//but just if the -R option is set
|
||||
//However, if the folders are the same, we can let it go as it will overwrite the files
|
||||
if (folders_flag) {
|
||||
if (strstr(parameters.output_folder, parameters.input_folder) != NULL) {
|
||||
if (strstr(parameters.output_folder, parameters.input_folder) != NULL
|
||||
&& strcmp(parameters.output_folder, parameters.input_folder) != 0
|
||||
&& parameters.recursive) {
|
||||
display_error(ERROR, 12);
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +176,10 @@ int start_compression(cclt_options *options, cs_image_pars *parameters)
|
|||
|
||||
for (int i = 0; i < options->files_count; i++) {
|
||||
char *filename = get_filename(options->input_files[i]);
|
||||
char *output_full_path;
|
||||
char *output_full_path = NULL;
|
||||
char *original_output_full_path = NULL;
|
||||
bool overwriting = false;
|
||||
off_t file_size = 0;
|
||||
//If we don't need to keep the structure, we put all the files in one folder by just the filename
|
||||
if (!options->keep_structure) {
|
||||
output_full_path = malloc((strlen(filename) + strlen(options->output_folder) + 1) * sizeof(char));
|
||||
|
@ -146,18 +187,23 @@ int start_compression(cclt_options *options, cs_image_pars *parameters)
|
|||
options->output_folder, filename);
|
||||
} else {
|
||||
/*
|
||||
* Otherwise, we nee to compute the whole directory structure
|
||||
* Otherwise, we need to compute the whole directory structure
|
||||
* We are sure we have a folder only as input, so that's the root
|
||||
* Just compute the subfolders without the filename, make them and append the filename
|
||||
* A piece of cake <3
|
||||
*/
|
||||
|
||||
size_t index = strspn(options->input_folder, options->input_files[i]) + 1;
|
||||
size_t index = strspn(options->input_folder, options->input_files[i]);
|
||||
size_t size = strlen(options->input_files[i]) - index - strlen(filename);
|
||||
char output_full_folder[strlen(options->output_folder) + size + 1];
|
||||
snprintf(output_full_folder, strlen(options->output_folder) + size + 1, "%s%s", options->output_folder, &options->input_files[i][index]);
|
||||
|
||||
snprintf(output_full_folder, strlen(options->output_folder) + size + 1, "%s%s",
|
||||
options->output_folder, &options->input_files[i][index]);
|
||||
output_full_path = malloc((strlen(output_full_folder) + strlen(filename) + 1) * sizeof(char));
|
||||
snprintf(output_full_path, strlen(output_full_folder) + strlen(filename) + 1, "%s%s", output_full_folder, filename);
|
||||
snprintf(output_full_path, strlen(output_full_folder) + strlen(filename) + 1, "%s%s",
|
||||
output_full_folder,
|
||||
filename);
|
||||
|
||||
mkpath(output_full_folder);
|
||||
}
|
||||
|
||||
|
@ -167,24 +213,47 @@ int start_compression(cclt_options *options, cs_image_pars *parameters)
|
|||
filename,
|
||||
output_full_path);
|
||||
|
||||
input_file_size = get_file_size(options->input_files[i]);
|
||||
options->input_total_size += input_file_size;
|
||||
if (cs_compress(options->input_files[i], output_full_path, parameters)) {
|
||||
compressed_files++;
|
||||
output_file_size = get_file_size(output_full_path);
|
||||
options->output_total_size += output_file_size;
|
||||
|
||||
char *human_input_size = get_human_size(input_file_size);
|
||||
char *human_output_size = get_human_size(output_file_size);
|
||||
|
||||
fprintf(stdout, "%s -> %s [%.2f%%]\n",
|
||||
human_input_size,
|
||||
human_output_size,
|
||||
((float) output_file_size - input_file_size) * 100 / input_file_size);
|
||||
} else {
|
||||
options->input_total_size -= get_file_size(options->input_files[i]);
|
||||
//If the file already exist, create a temporary file
|
||||
if (file_exists(output_full_path)) {
|
||||
original_output_full_path = strdup(output_full_path);
|
||||
output_full_path = realloc(output_full_path, (strlen(output_full_path) + 4) * sizeof(char));
|
||||
snprintf(output_full_path, (strlen(original_output_full_path) + 4), "%s.cs", original_output_full_path);
|
||||
overwriting = true;
|
||||
}
|
||||
|
||||
file_size = get_file_size(options->input_files[i]);
|
||||
if (file_size == 0) {
|
||||
//We could not open the file
|
||||
continue;
|
||||
}
|
||||
input_file_size = file_size;
|
||||
options->input_total_size += input_file_size;
|
||||
|
||||
//Prevent compression if running in dry mode
|
||||
if (!options->dry_run) {
|
||||
if (cs_compress(options->input_files[i], output_full_path, parameters)) {
|
||||
compressed_files++;
|
||||
output_file_size = get_file_size(output_full_path);
|
||||
options->output_total_size += output_file_size;
|
||||
|
||||
char *human_input_size = get_human_size(input_file_size);
|
||||
char *human_output_size = get_human_size(output_file_size);
|
||||
|
||||
fprintf(stdout, "%s -> %s [%.2f%%]\n",
|
||||
human_input_size,
|
||||
human_output_size,
|
||||
((float) output_file_size - input_file_size) * 100 / input_file_size);
|
||||
} else {
|
||||
options->input_total_size -= get_file_size(options->input_files[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//Rename if we were overwriting
|
||||
if (overwriting && !options->dry_run) {
|
||||
rename(output_full_path, original_output_full_path);
|
||||
}
|
||||
|
||||
free(original_output_full_path);
|
||||
free(output_full_path);
|
||||
}
|
||||
|
||||
|
|
12
src/helper.h
12
src/helper.h
|
@ -3,16 +3,24 @@
|
|||
|
||||
#include <caesium.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MAX_PATH_SIZE _MAX_PATH
|
||||
#else
|
||||
#include <limits.h>
|
||||
#define MAX_PATH_SIZE PATH_MAX
|
||||
#endif
|
||||
|
||||
typedef struct cclt_options
|
||||
{
|
||||
char **input_files;
|
||||
char *input_folder;
|
||||
char *output_folder;
|
||||
char input_folder[MAX_PATH_SIZE];
|
||||
char output_folder[MAX_PATH_SIZE];
|
||||
bool recursive;
|
||||
bool keep_structure;
|
||||
int files_count;
|
||||
off_t input_total_size;
|
||||
off_t output_total_size;
|
||||
bool dry_run;
|
||||
} cclt_options;
|
||||
|
||||
cclt_options parse_arguments(char *argv[], cs_image_pars *options);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
//Exit if no arguments
|
||||
//Exit if less than 2 arguments
|
||||
if (argc < 2) {
|
||||
print_help();
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -27,10 +27,8 @@ int main(int argc, char *argv[])
|
|||
|
||||
start_compression(&options, &compress_options);
|
||||
|
||||
//Cleanup the two memory allocated objects
|
||||
free(options.output_folder);
|
||||
//Cleanup the memory allocated objects
|
||||
free(options.input_files);
|
||||
free(options.input_folder);
|
||||
|
||||
//Get the difference
|
||||
diff = clock() - start;
|
||||
|
|
|
@ -99,11 +99,6 @@ int optparse(struct optparse *options, const char *optstring)
|
|||
int type = argtype(optstring, option[0]);
|
||||
char *next = options->argv[options->optind + 1];
|
||||
switch (type) {
|
||||
case -1: {
|
||||
options->optind++;
|
||||
char str[2] = {option[0]};
|
||||
return opterror(options, MSG_INVALID, str);
|
||||
}
|
||||
case OPTPARSE_NONE:
|
||||
if (option[1]) {
|
||||
options->subopt++;
|
||||
|
@ -134,8 +129,13 @@ int optparse(struct optparse *options, const char *optstring)
|
|||
else
|
||||
options->optarg = 0;
|
||||
return option[0];
|
||||
default:
|
||||
case -1: {
|
||||
options->optind++;
|
||||
char str[2] = {option[0]};
|
||||
return opterror(options, MSG_INVALID, str);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *optparse_arg(struct optparse *options)
|
||||
|
|
188
src/utils.c
188
src/utils.c
|
@ -4,6 +4,7 @@
|
|||
#include <caesium.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "tinydir.h"
|
||||
#include "error.h"
|
||||
|
@ -22,6 +23,7 @@ void print_help()
|
|||
"\t-o, --output\t\toutput folder\n"
|
||||
"\t-R, --recursive\t\tif input is a folder, scan subfolders too\n"
|
||||
"\t-S, --keep-structure\tkeep the folder structure, use with -R\n"
|
||||
"\t-d, --dry-run\t\tdo not really compress files but just show output paths\n"
|
||||
"\t-h, --help\t\tdisplay this help and exit\n"
|
||||
"\t-v, --version\t\toutput version information and exit\n\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -30,18 +32,18 @@ void print_help()
|
|||
bool is_directory(const char *path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
tinydir_dir dir;
|
||||
tinydir_dir dir;
|
||||
|
||||
return tinydir_open(&dir, path) != -1;
|
||||
return tinydir_open(&dir, path) != -1;
|
||||
|
||||
#else
|
||||
tinydir_file file;
|
||||
tinydir_file file;
|
||||
|
||||
if (tinydir_file_open(&file, path) == -1) {
|
||||
display_error(ERROR, 6);
|
||||
}
|
||||
if (tinydir_file_open(&file, path) == -1) {
|
||||
display_error(ERROR, 6);
|
||||
}
|
||||
|
||||
return (bool) file.is_dir;
|
||||
return (bool) file.is_dir;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -62,10 +64,10 @@ int scan_folder(const char *directory, cclt_options *options, bool recursive)
|
|||
} else {
|
||||
options->input_files = realloc(options->input_files, (options->files_count + 1) * sizeof(char *));
|
||||
options->input_files[options->files_count] = malloc((strlen(file.path) + 1) * sizeof(char));
|
||||
snprintf(options->input_files[options->files_count],
|
||||
strlen(file.path) + 1, "%s", file.path);
|
||||
snprintf(options->input_files[options->files_count],
|
||||
strlen(file.path) + 1, "%s", file.path);
|
||||
#ifdef _WIN32
|
||||
options->input_files[options->files_count] = str_replace(options->input_files[options->files_count], "/", "\\");
|
||||
options->input_files[options->files_count] = str_replace(options->input_files[options->files_count], "/", "\\");
|
||||
#endif
|
||||
options->files_count++;
|
||||
n++;
|
||||
|
@ -107,13 +109,10 @@ char *get_filename(char *full_path)
|
|||
|
||||
//Get just the filename
|
||||
tofree = strdup(full_path);
|
||||
//TODO change to strncpy
|
||||
strcpy(tofree, full_path);
|
||||
//TODO Windows?
|
||||
#ifdef _WIN32
|
||||
while ((token = strsep(&tofree, "\\")) != NULL) {
|
||||
while ((token = strsep(&tofree, "\\")) != NULL) {
|
||||
#else
|
||||
while ((token = strsep(&tofree, "/")) != NULL) {
|
||||
while ((token = strsep(&tofree, "/")) != NULL) {
|
||||
#endif
|
||||
if (tofree == NULL) {
|
||||
break;
|
||||
|
@ -127,19 +126,24 @@ char *get_filename(char *full_path)
|
|||
|
||||
off_t get_file_size(const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (f == NULL) {
|
||||
display_error(ERROR, 7);
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
unsigned long len = (unsigned long)ftell(f);
|
||||
fclose(f);
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (f == NULL) {
|
||||
display_error(WARNING, 7);
|
||||
return 0;
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
off_t len = ftell(f);
|
||||
fclose(f);
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
char *get_human_size(off_t size)
|
||||
{
|
||||
if (size == 0) {
|
||||
return "0.00 B";
|
||||
}
|
||||
|
||||
//We should not get more than TB images
|
||||
char *unit[5] = {"B", "KB", "MB", "GB", "TB"};
|
||||
//Index of the array containing the correct unit
|
||||
|
@ -158,88 +162,94 @@ char *get_human_size(off_t size)
|
|||
return final;
|
||||
}
|
||||
|
||||
bool file_exists(const char *file_path)
|
||||
{
|
||||
struct stat buffer;
|
||||
return (stat(file_path, &buffer) == 0);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
char *str_replace(char *orig, char *rep, char *with) {
|
||||
char *result; // the return string
|
||||
char *ins; // the next insert point
|
||||
char *tmp; // varies
|
||||
int len_rep; // length of rep (the string to remove)
|
||||
int len_with; // length of with (the string to replace rep with)
|
||||
int len_front; // distance between rep and end of last rep
|
||||
int count; // number of replacements
|
||||
char *result; // the return string
|
||||
char *ins; // the next insert point
|
||||
char *tmp; // varies
|
||||
int len_rep; // length of rep (the string to remove)
|
||||
int len_with; // length of with (the string to replace rep with)
|
||||
int len_front; // distance between rep and end of last rep
|
||||
int count; // number of replacements
|
||||
|
||||
if (!orig || !rep)
|
||||
return NULL;
|
||||
len_rep = strlen(rep);
|
||||
if (len_rep == 0)
|
||||
return NULL;
|
||||
if (!with)
|
||||
with = "";
|
||||
len_with = strlen(with);
|
||||
if (!orig || !rep)
|
||||
return NULL;
|
||||
len_rep = strlen(rep);
|
||||
if (len_rep == 0)
|
||||
return NULL;
|
||||
if (!with)
|
||||
with = "";
|
||||
len_with = strlen(with);
|
||||
|
||||
ins = orig;
|
||||
for (count = 0; tmp = strstr(ins, rep); ++count) {
|
||||
ins = tmp + len_rep;
|
||||
}
|
||||
ins = orig;
|
||||
for (count = 0; tmp = strstr(ins, rep); ++count) {
|
||||
ins = tmp + len_rep;
|
||||
}
|
||||
|
||||
tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
|
||||
tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
|
||||
|
||||
if (!result)
|
||||
return NULL;
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
while (count--) {
|
||||
ins = strstr(orig, rep);
|
||||
len_front = ins - orig;
|
||||
tmp = strncpy(tmp, orig, len_front) + len_front;
|
||||
tmp = strcpy(tmp, with) + len_with;
|
||||
orig += len_front + len_rep;
|
||||
}
|
||||
strcpy(tmp, orig);
|
||||
return result;
|
||||
while (count--) {
|
||||
ins = strstr(orig, rep);
|
||||
len_front = ins - orig;
|
||||
tmp = strncpy(tmp, orig, len_front) + len_front;
|
||||
tmp = strcpy(tmp, with) + len_with;
|
||||
orig += len_front + len_rep;
|
||||
}
|
||||
strcpy(tmp, orig);
|
||||
return result;
|
||||
}
|
||||
|
||||
char *strsep (char **stringp, const char *delim)
|
||||
{
|
||||
char *begin, *end;
|
||||
char *begin, *end;
|
||||
|
||||
begin = *stringp;
|
||||
if (begin == NULL)
|
||||
return NULL;
|
||||
begin = *stringp;
|
||||
if (begin == NULL)
|
||||
return NULL;
|
||||
|
||||
/* A frequent case is when the delimiter string contains only one
|
||||
character. Here we don't need to call the expensive `strpbrk'
|
||||
function and instead work using `strchr'. */
|
||||
if (delim[0] == '\0' || delim[1] == '\0')
|
||||
{
|
||||
char ch = delim[0];
|
||||
/* A frequent case is when the delimiter string contains only one
|
||||
character. Here we don't need to call the expensive `strpbrk'
|
||||
function and instead work using `strchr'. */
|
||||
if (delim[0] == '\0' || delim[1] == '\0')
|
||||
{
|
||||
char ch = delim[0];
|
||||
|
||||
if (ch == '\0')
|
||||
end = NULL;
|
||||
else
|
||||
{
|
||||
if (*begin == ch)
|
||||
end = begin;
|
||||
else if (*begin == '\0')
|
||||
end = NULL;
|
||||
else
|
||||
end = strchr (begin + 1, ch);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Find the end of the token. */
|
||||
end = strpbrk (begin, delim);
|
||||
if (ch == '\0')
|
||||
end = NULL;
|
||||
else
|
||||
{
|
||||
if (*begin == ch)
|
||||
end = begin;
|
||||
else if (*begin == '\0')
|
||||
end = NULL;
|
||||
else
|
||||
end = strchr (begin + 1, ch);
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Find the end of the token. */
|
||||
end = strpbrk (begin, delim);
|
||||
|
||||
if (end)
|
||||
{
|
||||
/* Terminate the token and set *STRINGP past NUL character. */
|
||||
*end++ = '\0';
|
||||
*stringp = end;
|
||||
}
|
||||
else
|
||||
/* No more delimiters; this is the last token. */
|
||||
*stringp = NULL;
|
||||
if (end)
|
||||
{
|
||||
/* Terminate the token and set *STRINGP past NUL character. */
|
||||
*end++ = '\0';
|
||||
*stringp = end;
|
||||
}
|
||||
else
|
||||
/* No more delimiters; this is the last token. */
|
||||
*stringp = NULL;
|
||||
|
||||
return begin;
|
||||
return begin;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,8 @@ char* get_human_size(off_t size);
|
|||
|
||||
int mkpath(const char *pathname);
|
||||
|
||||
bool file_exists(const char* file_path);
|
||||
|
||||
#ifdef _WIN32
|
||||
char *str_replace(char *orig, char *rep, char *with);
|
||||
char *strsep(char **stringp, const char *delim);
|
||||
|
|
Loading…
Reference in New Issue