summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorarchcrack <johndoe.arch@outlook.com>2021-01-27 22:34:16 -0300
committerarchcrack <johndoe.arch@outlook.com>2021-01-27 22:34:16 -0300
commitbec35039b9a3448deca3a093cc9a7f283e54e55c (patch)
tree08836856195a572862664d45fb1f92ec69b5030e
parentf0736436f8a0fd7fdddaa320a95b38107162e451 (diff)
0.27.1: Added Zstandard supportv0.27.1
-rw-r--r--.SRCINFO4
-rw-r--r--PKGBUILD4
-rw-r--r--clifm.c280
-rw-r--r--manpage14
4 files changed, 273 insertions, 29 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 72d6ef21..10ab657f 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,7 +1,7 @@
pkgbase = clifm
pkgdesc = The KISS file manager: cli-based, ultra-lightweight, and lightning fast
- pkgver = 0.27.0
- pkgrel = 2
+ pkgver = 0.27.1
+ pkgrel = 1
url = https://github.com/leo-arch/clifm
arch = any
license = GPL2
diff --git a/PKGBUILD b/PKGBUILD
index 41287c5a..15612ee6 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -1,8 +1,8 @@
# Maintainer: archcrack <johndoe.arch@outlook.com>
pkgname=clifm
-pkgver=0.27.0
-pkgrel=2
+pkgver=0.27.1
+pkgrel=1
pkgdesc="The KISS file manager: cli-based, ultra-lightweight, and lightning fast"
arch=(any)
url="https://github.com/leo-arch/clifm"
diff --git a/clifm.c b/clifm.c
index 5878d113..edbc9641 100644
--- a/clifm.c
+++ b/clifm.c
@@ -151,7 +151,7 @@ in FreeBSD, but is deprecated */
/* If no formatting, puts (or write) is faster than printf */
/* #define CLEAR puts("\x1b[c") */
#define CLEAR write(STDOUT_FILENO, "\ec", 3)
-#define VERSION "0.27.0"
+#define VERSION "0.27.1"
#define AUTHOR "L. Abramovich"
#define CONTACT "johndoe.arch@outlook.com"
#define WEBSITE "https://github.com/leo-arch/clifm"
@@ -390,6 +390,7 @@ int mtime_sort(const struct dirent **a, const struct dirent **b);
int bulk_rename(char **args);
int archiver(char **args, char mode);
+int zstandard(char *in_file, char *out_file, char mode, char op);
int is_compressed(char *file);
/* Still under development */
@@ -1128,7 +1129,9 @@ is_compressed(char *file)
int compressed = 0;
if (access(ARCHIVER_TMP_FILE, F_OK) == 0) {
+
file_fp = fopen(ARCHIVER_TMP_FILE, "r");
+
if (file_fp) {
char line[255] = "";
fgets(line, sizeof(line), file_fp);
@@ -1152,11 +1155,129 @@ is_compressed(char *file)
}
int
+zstandard(char *in_file, char *out_file, char mode, char op)
+/* If MODE is 'c', compress IN_FILE producing a zstandard compressed
+ * file named OUT_FILE. If MODE is 'd', extract, test or get
+ * information about IN_FILE. Returns zero on success and one on
+ * error */
+{
+ int exit_status = EXIT_SUCCESS;
+
+ char *deq_file = dequote_str(in_file, 0);
+
+ if (!deq_file) {
+ fprintf(stderr, "archiver: '%s': Error dequoting file\n",
+ in_file);
+ return EXIT_FAILURE;
+ }
+
+ if (mode == 'c') {
+
+ if (out_file) {
+ char *cmd[] = { "zstd", "-zo", out_file, deq_file, NULL };
+ if (launch_execve(cmd, FOREGROUND) != EXIT_SUCCESS)
+ exit_status = EXIT_FAILURE;
+ }
+
+ else {
+ char *cmd[] = { "zstd", "-z", deq_file, NULL };
+ if (launch_execve(cmd, FOREGROUND) != EXIT_SUCCESS)
+ exit_status = EXIT_FAILURE;
+ }
+
+ free(deq_file);
+ return exit_status;
+ }
+
+ /* mode == 'd' */
+
+ /* op is non-zero when multiple files, including at least one
+ * zst file, are passed to the archiver function */
+ if (op != 0) {
+ char option[3] = "";
+
+ switch(op) {
+ case 'e': strcpy(option, "-d"); break;
+ case 't': strcpy(option, "-t"); break;
+ case 'i': strcpy(option, "-l"); break;
+ }
+
+ char *cmd[] = { "zstd", option, deq_file, NULL };
+
+ exit_status = launch_execve(cmd, FOREGROUND);
+
+ free(deq_file);
+
+ if (exit_status != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+ }
+
+
+ printf("%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n",
+ bold, NC, bold, NC, bold, NC, bold, NC);
+
+ char *operation = (char *)NULL;
+
+ while (!operation) {
+ operation = rl_no_hist(_("Operation: "));
+
+ if (!operation)
+ continue;
+
+ if (operation && (!operation[0] || operation[1] != '\0')) {
+ free(operation);
+ operation = (char *)NULL;
+ continue;
+ }
+
+ switch(*operation) {
+ case 'e': {
+ char *cmd[] = { "zstd", "-d", deq_file, NULL };
+ if (launch_execve(cmd, FOREGROUND) != EXIT_SUCCESS)
+ exit_status = EXIT_FAILURE;
+ }
+ break;
+
+ case 't': {
+ char *cmd[] = { "zstd", "-t", deq_file, NULL };
+ if (launch_execve(cmd, FOREGROUND) != EXIT_SUCCESS)
+ exit_status = EXIT_FAILURE;
+ }
+ break;
+
+ case 'i': {
+ char *cmd[] = { "zstd", "-l", deq_file, NULL };
+ if (launch_execve(cmd, FOREGROUND) != EXIT_SUCCESS)
+ exit_status = EXIT_FAILURE;
+ }
+ break;
+
+ case 'q':
+ free(operation);
+ free(deq_file);
+ return EXIT_SUCCESS;
+
+ default:
+ free(operation);
+ operation = (char *)NULL;
+ break;
+ }
+ }
+
+ free(operation);
+ free(deq_file);
+
+ return exit_status;
+}
+
+int
archiver(char **args, char mode)
-/* Handle archives or compressed files (ARGS) according to MODE: 'c'
- * for compression and 'd' for decompression (including listing,
- * extracting, repacking, and mounting). Returns zero on success and
- * one on error */
+/* Handle archives and/or compressed files (ARGS) according to MODE:
+ * 'c' for archiving/compression, and 'd' for dearchiving/decompression
+ * (including listing, extracting, repacking, and mounting). Returns
+ * zero on success and one on error */
{
size_t i;
int uncompressed = 0, exit_status = EXIT_SUCCESS;
@@ -1167,15 +1288,16 @@ archiver(char **args, char mode)
if (mode == 'c') {
/* ##################################
- * # COMPRESSION #
+ * # 1 - COMPRESSION #
* ##################################*/
- /* Ask for archive name */
- puts(_("Use extension to specify archive type.\n"
+ /* Get archive name/type */
+
+ puts(_("Use extension to specify archive/compression type.\n"
"Defaults to .tar.gz"));
char *name = (char *)NULL;
while (!name) {
- name = rl_no_hist(_("Archive name ('q' to quit): "));
+ name = rl_no_hist(_("Filename ('q' to quit): "));
if (!name)
continue;
@@ -1192,6 +1314,43 @@ archiver(char **args, char mode)
}
}
+ /* ##########################
+ * # ZSTANDARD #
+ * ########################## */
+
+ char *ret = strrchr(name, '.');
+ if (strcmp(ret, ".zst") == 0) {
+
+ /* Multiple files */
+ if (args[2]) {
+
+ printf("\n%sNOTE%s: Zstandard does not support "
+ "compression of multiple files into one single "
+ "compressed file. Files will be compressed rather "
+ "into multiple compressed files using original "
+ "filenames\n", bold, NC);
+
+ for (i = 1; args[i]; i++) {
+ if (zstandard(args[i], NULL, 'c', 0)
+ != EXIT_SUCCESS)
+ exit_status = EXIT_FAILURE;
+ }
+ }
+
+ /* Only one file */
+ else
+ exit_status = zstandard(args[1], name, 'c', 0);
+
+ free(name);
+
+ return exit_status;
+ }
+
+
+ /* ##########################
+ * # NO ZSTANDARD #
+ * ########################## */
+
/* Escape the string, if needed */
char *esc_name = escape_str(name);
free(name);
@@ -1208,6 +1367,7 @@ archiver(char **args, char mode)
size_t cmd_len = strlen(esc_name) + 10 + ((!ext_ok) ? 8 : 0);
cmd = (char *)xcalloc(cmd_len, sizeof(char));
+
/* If name has no extension, add the default */
sprintf(cmd, "atool -a %s%s", esc_name, (!ext_ok)
? ".tar.gz" : "");
@@ -1228,12 +1388,99 @@ archiver(char **args, char mode)
return exit_status;
}
+
/* mode == 'd' */
/* ##################################
- * # DECOMPRESSION #
+ * # 2 - DECOMPRESSION #
* ##################################*/
+ /* Check if we have at least one Zstandard file */
+
+ int zst_index = -1;
+ size_t files_num = 0;
+
+ for (i = 1; args[i]; i++) {
+ files_num++;
+ if (args[i][strlen(args[i]) -1] == 't') {
+ char *ret = strrchr(args[i], '.');
+ if (ret) {
+ if (strcmp(ret, ".zst") == 0)
+ zst_index = i;
+ }
+ }
+ }
+
+ /* ##########################
+ * # ZSTANDARD #
+ * ########################## */
+
+ if (zst_index != -1) {
+
+ /* Multiple files */
+ if (files_num > 1) {
+
+ printf("%sNOTE%s: Using Zstandard\n", bold, NC);
+ printf("%s[e]%sxtract %s[t]%sest %s[i]%snfo %s[q]%suit\n",
+ bold, NC, bold, NC, bold, NC, bold, NC);
+
+ char *operation = (char *)NULL;
+ char sel_op = 0;
+ while(!operation) {
+ operation = rl_no_hist("Operation: ");
+
+ if (!operation)
+ continue;
+
+ if (operation && (!operation[0]
+ || operation[1] != '\0')) {
+ free(operation);
+ operation = (char *)NULL;
+ continue;
+ }
+
+ switch(*operation) {
+ case 'e':
+ case 't':
+ case 'i':
+ sel_op = *operation;
+ break;
+
+ case 'q':
+ free(operation);
+ return EXIT_SUCCESS;
+
+ default:
+ free(operation);
+ operation = (char *)NULL;
+ break;
+ }
+ }
+
+ for (i = 1; args[i]; i++) {
+ if (zstandard(args[i], NULL, 'd', sel_op)
+ != EXIT_SUCCESS);
+ exit_status = EXIT_FAILURE;
+ }
+
+ free(operation);
+ return exit_status;
+ }
+
+ /* Just one file */
+ else {
+ if (zstandard(args[zst_index], NULL, 'd', 0) != EXIT_SUCCESS)
+ exit_status = EXIT_FAILURE;
+
+ return exit_status;
+ }
+ }
+
+
+ /* ##########################
+ * # NO ZSTANDARD #
+ * ########################## */
+
/* 1) Get operation to be performed */
printf(_("%s[e]%sxtract %s[E]%sxtract-to-dir %s[l]%sist "
"%s[m]%sount %s[r]%sepack %s[q]%suit\n"), bold, NC, bold,
@@ -1241,7 +1488,6 @@ archiver(char **args, char mode)
char *operation = (char *)NULL;
char sel_op = 0;
- size_t files_num = 0;
while (!operation) {
operation = rl_no_hist(_("Operation: "));
@@ -1317,7 +1563,7 @@ archiver(char **args, char mode)
if (ret == 1) {
fprintf(stderr, _("archiver: '%s': Not an "
- "archive\n"), args[i]);
+ "archive/compressed file\n"), args[i]);
continue;
}
@@ -1337,8 +1583,6 @@ archiver(char **args, char mode)
/* Dequote filenames, if neccessary */
for (i = 1; args[i]; i++) {
- files_num++;
-
if (strchr(args[i], '\\')) {
char *deq_name = dequote_str(args[i], 0);
@@ -1392,7 +1636,7 @@ archiver(char **args, char mode)
if (ret == 1) {
fprintf(stderr, _("archiver: '%s': Not an "
- "archive\n"), args[i]);
+ "archive/compressed file\n"), args[i]);
continue;
}
@@ -1455,7 +1699,7 @@ archiver(char **args, char mode)
if (ret == 1) {
fprintf(stderr, _("archiver: '%s': Not an "
- "archive\n"), args[i]);
+ "archive/compressed file\n"), args[i]);
continue;
}
@@ -1520,12 +1764,12 @@ archiver(char **args, char mode)
/* ########## REPACK ############## */
case 'r': {
- /* Ask for new archive format */
+ /* Ask for new archive/compression format */
puts("Enter 'q' to quit");
char *format = (char *)NULL;
while (!format) {
- format = rl_no_hist(_("New archive format "
+ format = rl_no_hist(_("New format "
"(Ex: .tar.xz): "));
if (!format)
continue;
diff --git a/manpage b/manpage
index 50344ea8..4fc30e23 100644
--- a/manpage
+++ b/manpage
@@ -51,7 +51,7 @@ List of CliFM features:
20) Resource opener
21) Multiple sorting methods and reverse sorting
22) Bulk rename
- 23) Archives support
+ 23) Archiving and compression support
.SH RATIONALE
When it comes to software, Unix/GNU-Linux is no doubt the land of Freedom, and Freedom, so to say, is the elder sister of Choice and Alternative. Now, regarding File Managers (FM), broadly understood as a computer program providing a user interface to manage files and directories, we either stick to the CLI or Command Line Interface (the Linux built-in console or a terminal emulator running a bare shell) or choose rather some kind of graphical alternative (be it a GUI program, in the strictest sense, or a curses-based one). In between, however, there is nothing, or at least, almost nothing. But as the old Italian saying goes: "There is no two without three".
@@ -182,9 +182,9 @@ rename at once all files passed as arguments to the function. It accepts single
.TP
.B ac, ad \fRELN/FILE ... n
-compress and decompress one or multiple files and/or directories. The archiver function brings two modes: \fBac\fR, to generate archives or compressed files, and \fBad\fR, to decompress archives, either just listing, extracting, recompressing, or mounting their content. In this latter case, the mountpoint used automatically is \fI$HOME/.config/clifm/PROFILE/mounts/ARCHIVE_NAME\fR. The function accepts single and multiple filenames, wildcards, ELN ranges, and the 'sel' keyword. For example: 'ac sel', 'ac 4-25 myfile', or 'ad *.tar.gz'.
+archive/compress and dearchive/decompress one or multiple files and/or directories. The archiver function brings two modes: \fBac\fR, to generate archives or compressed files, and \fBad\fR, to decompress or dearchive files, either just listing, extracting, recompressing, or mounting their content. In this latter case, the mountpoint used automatically is \fI$HOME/.config/clifm/PROFILE/mounts/ARCHIVE_NAME\fR. The function accepts single and multiple filenames, wildcards, ELN ranges, and the 'sel' keyword. For example: 'ac sel', 'ac 4-25 myfile', or 'ad *.tar.gz'.Multiple archive/compression formats are supported, including Zstandard.
.sp
-The archive mount function depends on \fBarchivemount\fR, while the remaining functions depend on \fBatool\fR and other third-party utilities for achive formats support, for example, \fBp7zip\fR. For more information consult \fBatool(1)\fR and \fBarchivemount(1)\fR.
+The archive mount function depends on \fBarchivemount\fR, while the remaining functions depend on \fBatool\fR and other third-party utilities for achive formats support, for example, \fBp7zip\fR. For more information consult \fBatool(1)\fR, \fBarchivemount(1)\fR, and \fBzstd(1)\fR.
.TP
.B b, back \fR[h, hist] [clear] [!ELN]
@@ -573,8 +573,8 @@ The file contains a series of fields separated by a colon in the following way:
\fBMessages log file:\fR \fI~/.config.clifm/profile_name/messages.cfm\fR
A file containing a list of system messages, either errors, warnings, or simple notices. The messages log format is: [date] message.
-.SH AUTHOR
-L.M. Abramovich (https://github.com/leo-arch)
+.SH BUGS AND FEATURE REQUESTS
+Report at: https://github.com/leo-arch/clifm/issues
-.SH BUG REPORTS
-johndoe.arch@outlook.com
+.SH AUTHOR
+L. M. Abramovich