mirror of
https://github.com/weechat/weechat.git
synced 2026-07-07 02:03:13 +02:00
api: add function file_compress
This commit is contained in:
@@ -29,6 +29,7 @@ New features::
|
||||
* api: add function crypto_hash_file
|
||||
* api: add support of priority in function hook_line (issue #1821)
|
||||
* api: add function string_parse_size
|
||||
* api: add function file_compress
|
||||
* buflist: add variable `${hotlist_priority_number}` (integer version of `${hotlist_priority}`)
|
||||
* irc: display SETNAME command in channels and private buffers, add options irc.color.message_setname and irc.look.smart_filter_setname (issue #1805)
|
||||
* irc: add option irc.look.display_pv_nick_change
|
||||
|
||||
@@ -4189,6 +4189,47 @@ if (weechat_file_copy ("/tmp/test.txt", "/path/to/test2.txt"))
|
||||
[NOTE]
|
||||
This function is not available in scripting API.
|
||||
|
||||
==== file_compress
|
||||
|
||||
_WeeChat ≥ 3.7._
|
||||
|
||||
Compress a file with gzip or zstd.
|
||||
|
||||
Prototype:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
int weechat_file_compress (const char *from, const char *to,
|
||||
const char *compressor, int compression_level);
|
||||
----
|
||||
|
||||
Arguments:
|
||||
|
||||
* _from_: source file
|
||||
* _to_: destination file
|
||||
* _compressor_: the compressor to use, one of:
|
||||
** _gzip_: gzip compression
|
||||
** _zstd_: zstandard compression
|
||||
* _compression_level_: compression level, between 1 (fast, low compression) to
|
||||
100 (slow, best compression)
|
||||
|
||||
Return value:
|
||||
|
||||
* 1 if OK, 0 if error
|
||||
|
||||
C example:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
if (weechat_file_compress ("/tmp/test.txt", "/tmp/test.txt.zst", "zstd", 50))
|
||||
{
|
||||
/* OK */
|
||||
}
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
This function is not available in scripting API.
|
||||
|
||||
[[util]]
|
||||
=== Util
|
||||
|
||||
|
||||
@@ -4258,6 +4258,47 @@ if (weechat_file_copy ("/tmp/test.txt", "/path/to/test2.txt"))
|
||||
[NOTE]
|
||||
Cette fonction n'est pas disponible dans l'API script.
|
||||
|
||||
==== file_compress
|
||||
|
||||
_WeeChat ≥ 3.7._
|
||||
|
||||
Compresser un fichier avec gzip ou zstd.
|
||||
|
||||
Prototype :
|
||||
|
||||
[source,c]
|
||||
----
|
||||
int weechat_file_compress (const char *from, const char *to,
|
||||
const char *compressor, int compression_level);
|
||||
----
|
||||
|
||||
Paramètres :
|
||||
|
||||
* _from_ : fichier source
|
||||
* _to_ : fichier cible
|
||||
* _compressor_ : le compresseur à utiliser, un parmi :
|
||||
** _gzip_ : compression gzip
|
||||
** _zstd_ : compression zstandard
|
||||
* _compression_level_ : niveau de compression, entre 1 (rapide, peu de
|
||||
compression) à 100 (lent, meilleure compression)
|
||||
|
||||
Valeur de retour :
|
||||
|
||||
* 1 si OK, 0 si erreur
|
||||
|
||||
Exemple en C :
|
||||
|
||||
[source,c]
|
||||
----
|
||||
if (weechat_file_compress ("/tmp/test.txt", "/tmp/test.txt.zst", "zstd", 50))
|
||||
{
|
||||
/* OK */
|
||||
}
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
Cette fonction n'est pas disponible dans l'API script.
|
||||
|
||||
[[util]]
|
||||
=== Util
|
||||
|
||||
|
||||
@@ -4342,6 +4342,48 @@ if (weechat_file_copy ("/tmp/test.txt", "/path/to/test2.txt"))
|
||||
[NOTE]
|
||||
Questa funzione non è disponibile nelle API per lo scripting.
|
||||
|
||||
// TRANSLATION MISSING
|
||||
==== file_compress
|
||||
|
||||
_WeeChat ≥ 3.7._
|
||||
|
||||
Compress a file with gzip or zstd.
|
||||
|
||||
Prototipo:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
int weechat_file_compress (const char *from, const char *to,
|
||||
const char *compressor, int compression_level);
|
||||
----
|
||||
|
||||
Argomenti:
|
||||
|
||||
* _from_: source file
|
||||
* _to_: destination file
|
||||
* _compressor_: the compressor to use, one of:
|
||||
** _gzip_: gzip compression
|
||||
** _zstd_: zstandard compression
|
||||
* _compression_level_: compression level, between 1 (fast, low compression) to
|
||||
100 (slow, best compression)
|
||||
|
||||
Valore restituito:
|
||||
|
||||
* 1 if OK, 0 if error
|
||||
|
||||
Esempio in C:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
if (weechat_file_compress ("/tmp/test.txt", "/tmp/test.txt.zst", "zstd", 50))
|
||||
{
|
||||
/* OK */
|
||||
}
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
Questa funzione non è disponibile nelle API per lo scripting.
|
||||
|
||||
[[util]]
|
||||
=== Utilità
|
||||
|
||||
|
||||
@@ -4258,6 +4258,48 @@ if (weechat_file_copy ("/tmp/test.txt", "/path/to/test2.txt"))
|
||||
[NOTE]
|
||||
スクリプト API ではこの関数を利用できません。
|
||||
|
||||
// TRANSLATION MISSING
|
||||
==== file_compress
|
||||
|
||||
_WeeChat ≥ 3.7._
|
||||
|
||||
Compress a file with gzip or zstd.
|
||||
|
||||
プロトタイプ:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
int weechat_file_compress (const char *from, const char *to,
|
||||
const char *compressor, int compression_level);
|
||||
----
|
||||
|
||||
引数:
|
||||
|
||||
* _from_: source file
|
||||
* _to_: destination file
|
||||
* _compressor_: the compressor to use, one of:
|
||||
** _gzip_: gzip compression
|
||||
** _zstd_: zstandard compression
|
||||
* _compression_level_: compression level, between 1 (fast, low compression) to
|
||||
100 (slow, best compression)
|
||||
|
||||
戻り値:
|
||||
|
||||
* 1 if OK, 0 if error
|
||||
|
||||
C 言語での使用例:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
if (weechat_file_compress ("/tmp/test.txt", "/tmp/test.txt.zst", "zstd", 50))
|
||||
{
|
||||
/* OK */
|
||||
}
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
スクリプト API ではこの関数を利用できません。
|
||||
|
||||
[[util]]
|
||||
=== ユーティリティ
|
||||
|
||||
|
||||
@@ -4053,6 +4053,48 @@ if (weechat_file_copy ("/tmp/test.txt", "/path/to/test2.txt"))
|
||||
|
||||
Неке корисне функције.
|
||||
|
||||
// TRANSLATION MISSING
|
||||
==== file_compress
|
||||
|
||||
_WeeChat ≥ 3.7._
|
||||
|
||||
Compress a file with gzip or zstd.
|
||||
|
||||
Прототип:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
int weechat_file_compress (const char *from, const char *to,
|
||||
const char *compressor, int compression_level);
|
||||
----
|
||||
|
||||
Аргументи:
|
||||
|
||||
* _from_: изворишни фајл
|
||||
* _to_: одредишни фајл
|
||||
* _compressor_: the compressor to use, one of:
|
||||
** _gzip_: gzip compression
|
||||
** _zstd_: zstandard compression
|
||||
* _compression_level_: compression level, between 1 (fast, low compression) to
|
||||
100 (slow, best compression)
|
||||
|
||||
Повратна вредност:
|
||||
|
||||
* 1 ако је копирање OK, 0 у случају грешке
|
||||
|
||||
C пример:
|
||||
|
||||
[source,c]
|
||||
----
|
||||
if (weechat_file_compress ("/tmp/test.txt", "/tmp/test.txt.zst", "zstd", 50))
|
||||
{
|
||||
/* OK */
|
||||
}
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
Ова функција није доступна у API скриптовања.
|
||||
|
||||
==== util_timeval_cmp
|
||||
|
||||
Пореди две „timeval” структуре.
|
||||
|
||||
@@ -88,6 +88,8 @@ include_directories(${GNUTLS_INCLUDE_PATH})
|
||||
|
||||
include_directories(${CURL_INCLUDE_DIRS})
|
||||
|
||||
include_directories(${ZSTD_INCLUDE_DIRS})
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR})
|
||||
add_library(weechat_core STATIC ${LIB_CORE_SRC})
|
||||
target_link_libraries(weechat_core coverage_config)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
AM_CPPFLAGS = -DLOCALEDIR=\"$(datadir)/locale\" $(GCRYPT_CFLAGS) $(GNUTLS_CFLAGS) $(CURL_CFLAGS)
|
||||
AM_CPPFLAGS = -DLOCALEDIR=\"$(datadir)/locale\" $(GCRYPT_CFLAGS) $(GNUTLS_CFLAGS) $(CURL_CFLAGS) $(ZLIB_CFLAGS) $(ZSTD_CFLAGS)
|
||||
|
||||
noinst_LIBRARIES = lib_weechat_core.a
|
||||
|
||||
|
||||
+588
-318
@@ -44,6 +44,8 @@
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <ftw.h>
|
||||
#include <zlib.h>
|
||||
#include <zstd.h>
|
||||
|
||||
#include "weechat.h"
|
||||
#include "wee-config.h"
|
||||
@@ -293,324 +295,6 @@ dir_rmtree (const char *directory)
|
||||
return (rc == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds files in a directory and executes a function on each file.
|
||||
*/
|
||||
|
||||
void
|
||||
dir_exec_on_files (const char *directory, int recurse_subdirs,
|
||||
int hidden_files,
|
||||
void (*callback)(void *data, const char *filename),
|
||||
void *callback_data)
|
||||
{
|
||||
char complete_filename[PATH_MAX];
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
struct stat statbuf;
|
||||
|
||||
if (!directory || !callback)
|
||||
return;
|
||||
|
||||
dir = opendir (directory);
|
||||
if (dir)
|
||||
{
|
||||
while ((entry = readdir (dir)))
|
||||
{
|
||||
if (hidden_files || (entry->d_name[0] != '.'))
|
||||
{
|
||||
snprintf (complete_filename, sizeof (complete_filename),
|
||||
"%s/%s", directory, entry->d_name);
|
||||
lstat (complete_filename, &statbuf);
|
||||
if (S_ISDIR(statbuf.st_mode))
|
||||
{
|
||||
if (recurse_subdirs
|
||||
&& (strcmp (entry->d_name, ".") != 0)
|
||||
&& (strcmp (entry->d_name, "..") != 0))
|
||||
{
|
||||
dir_exec_on_files (complete_filename, 1, hidden_files,
|
||||
callback, callback_data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*callback) (callback_data, complete_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir (dir);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Searches for the full name of a WeeChat library with name and extension
|
||||
* (searches first in WeeChat user's dir, then WeeChat global lib directory).
|
||||
*
|
||||
* Returns name of library found, NULL if not found.
|
||||
*
|
||||
* Note: result must be freed after use (if not NULL).
|
||||
*/
|
||||
|
||||
char *
|
||||
dir_search_full_lib_name_ext (const char *filename, const char *extension,
|
||||
const char *plugins_dir)
|
||||
{
|
||||
char *name_with_ext, *final_name, *extra_libdir;
|
||||
int length;
|
||||
struct stat st;
|
||||
|
||||
length = strlen (filename) + strlen (extension) + 1;
|
||||
name_with_ext = malloc (length);
|
||||
if (!name_with_ext)
|
||||
return NULL;
|
||||
snprintf (name_with_ext, length,
|
||||
"%s%s",
|
||||
filename,
|
||||
(strchr (filename, '.')) ? "" : extension);
|
||||
|
||||
/* try libdir from environment variable WEECHAT_EXTRA_LIBDIR */
|
||||
extra_libdir = getenv (WEECHAT_EXTRA_LIBDIR);
|
||||
if (extra_libdir && extra_libdir[0])
|
||||
{
|
||||
length = strlen (extra_libdir) + strlen (name_with_ext) +
|
||||
strlen (plugins_dir) + 16;
|
||||
final_name = malloc (length);
|
||||
if (!final_name)
|
||||
{
|
||||
free (name_with_ext);
|
||||
return NULL;
|
||||
}
|
||||
snprintf (final_name, length,
|
||||
"%s%s%s%s%s",
|
||||
extra_libdir,
|
||||
DIR_SEPARATOR,
|
||||
plugins_dir,
|
||||
DIR_SEPARATOR,
|
||||
name_with_ext);
|
||||
if ((stat (final_name, &st) == 0) && (st.st_size > 0))
|
||||
{
|
||||
free (name_with_ext);
|
||||
return final_name;
|
||||
}
|
||||
free (final_name);
|
||||
}
|
||||
|
||||
/* try WeeChat user's dir */
|
||||
length = strlen (weechat_data_dir) + strlen (name_with_ext) +
|
||||
strlen (plugins_dir) + 16;
|
||||
final_name = malloc (length);
|
||||
if (!final_name)
|
||||
{
|
||||
free (name_with_ext);
|
||||
return NULL;
|
||||
}
|
||||
snprintf (final_name, length,
|
||||
"%s%s%s%s%s",
|
||||
weechat_data_dir,
|
||||
DIR_SEPARATOR,
|
||||
plugins_dir,
|
||||
DIR_SEPARATOR,
|
||||
name_with_ext);
|
||||
if ((stat (final_name, &st) == 0) && (st.st_size > 0))
|
||||
{
|
||||
free (name_with_ext);
|
||||
return final_name;
|
||||
}
|
||||
free (final_name);
|
||||
|
||||
/* try WeeChat global lib dir */
|
||||
length = strlen (WEECHAT_LIBDIR) + strlen (name_with_ext) +
|
||||
strlen (plugins_dir) + 16;
|
||||
final_name = malloc (length);
|
||||
if (!final_name)
|
||||
{
|
||||
free (name_with_ext);
|
||||
return NULL;
|
||||
}
|
||||
snprintf (final_name, length,
|
||||
"%s%s%s%s%s",
|
||||
WEECHAT_LIBDIR,
|
||||
DIR_SEPARATOR,
|
||||
plugins_dir,
|
||||
DIR_SEPARATOR,
|
||||
name_with_ext);
|
||||
if ((stat (final_name, &st) == 0) && (st.st_size > 0))
|
||||
{
|
||||
free (name_with_ext);
|
||||
return final_name;
|
||||
}
|
||||
free (final_name);
|
||||
|
||||
free (name_with_ext);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Searches for the full name of a WeeChat library with name.
|
||||
*
|
||||
* All extensions listed in option "weechat.plugin.extension" are tested.
|
||||
*
|
||||
* Note: result must be freed after use (if not NULL).
|
||||
*/
|
||||
|
||||
char *
|
||||
dir_search_full_lib_name (const char *filename, const char *plugins_dir)
|
||||
{
|
||||
char *filename2, *full_name;
|
||||
int i;
|
||||
|
||||
/* expand home in filename */
|
||||
filename2 = string_expand_home (filename);
|
||||
if (!filename2)
|
||||
return NULL;
|
||||
|
||||
/* if full path, return it */
|
||||
if (strchr (filename2, '/') || strchr (filename2, '\\'))
|
||||
return filename2;
|
||||
|
||||
if (config_plugin_extensions)
|
||||
{
|
||||
for (i = 0; i < config_num_plugin_extensions; i++)
|
||||
{
|
||||
full_name = dir_search_full_lib_name_ext (
|
||||
filename2,
|
||||
config_plugin_extensions[i],
|
||||
plugins_dir);
|
||||
if (full_name)
|
||||
{
|
||||
free (filename2);
|
||||
return full_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
full_name = dir_search_full_lib_name_ext (filename2, "", plugins_dir);
|
||||
if (full_name)
|
||||
{
|
||||
free (filename2);
|
||||
return full_name;
|
||||
}
|
||||
}
|
||||
|
||||
free (filename2);
|
||||
|
||||
return strdup (filename);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads content of a file.
|
||||
*
|
||||
* Returns an allocated buffer with the content of file, NULL if error.
|
||||
*
|
||||
* Note: result must be freed after use.
|
||||
*/
|
||||
|
||||
char *
|
||||
dir_file_get_content (const char *filename)
|
||||
{
|
||||
char *buffer, *buffer2;
|
||||
FILE *f;
|
||||
size_t count, fp;
|
||||
|
||||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
buffer = NULL;
|
||||
fp = 0;
|
||||
|
||||
f = fopen (filename, "r");
|
||||
if (!f)
|
||||
goto error;
|
||||
|
||||
while (!feof (f))
|
||||
{
|
||||
if (fp > SIZE_MAX - (1024 * sizeof (char)))
|
||||
goto error;
|
||||
buffer2 = (char *) realloc (buffer, (fp + (1024 * sizeof (char))));
|
||||
if (!buffer2)
|
||||
goto error;
|
||||
buffer = buffer2;
|
||||
count = fread (&buffer[fp], sizeof (char), 1024, f);
|
||||
if (count <= 0)
|
||||
goto error;
|
||||
fp += count;
|
||||
}
|
||||
if (fp > SIZE_MAX - sizeof (char))
|
||||
goto error;
|
||||
buffer2 = (char *) realloc (buffer, fp + sizeof (char));
|
||||
if (!buffer2)
|
||||
goto error;
|
||||
buffer = buffer2;
|
||||
buffer[fp] = '\0';
|
||||
fclose (f);
|
||||
|
||||
return buffer;
|
||||
|
||||
error:
|
||||
if (buffer)
|
||||
free (buffer);
|
||||
if (f)
|
||||
fclose (f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a file to another location.
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
dir_file_copy (const char *from, const char *to)
|
||||
{
|
||||
FILE *src, *dst;
|
||||
char *buffer;
|
||||
int rc;
|
||||
size_t count;
|
||||
|
||||
rc = 0;
|
||||
buffer = NULL;
|
||||
src = NULL;
|
||||
dst = NULL;
|
||||
|
||||
if (!from || !from[0] || !to || !to[0])
|
||||
goto end;
|
||||
|
||||
buffer = malloc (65536);
|
||||
if (!buffer)
|
||||
goto end;
|
||||
|
||||
src = fopen (from, "rb");
|
||||
if (!src)
|
||||
goto end;
|
||||
dst = fopen (to, "wb");
|
||||
if (!dst)
|
||||
goto end;
|
||||
|
||||
while (!feof (src))
|
||||
{
|
||||
count = fread (buffer, 1, 65536, src);
|
||||
if (count <= 0)
|
||||
goto end;
|
||||
if (fwrite (buffer, 1, count, dst) <= 0)
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
|
||||
end:
|
||||
if (buffer)
|
||||
free (buffer);
|
||||
if (src)
|
||||
fclose (src);
|
||||
if (dst)
|
||||
fclose (dst);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Uses one or four different paths for WeeChat home directories.
|
||||
*
|
||||
@@ -1038,3 +722,589 @@ dir_get_string_home_dirs ()
|
||||
|
||||
return string_rebuild_split_string ((const char **)dirs, ":", 0, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds files in a directory and executes a function on each file.
|
||||
*/
|
||||
|
||||
void
|
||||
dir_exec_on_files (const char *directory, int recurse_subdirs,
|
||||
int hidden_files,
|
||||
void (*callback)(void *data, const char *filename),
|
||||
void *callback_data)
|
||||
{
|
||||
char complete_filename[PATH_MAX];
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
struct stat statbuf;
|
||||
|
||||
if (!directory || !callback)
|
||||
return;
|
||||
|
||||
dir = opendir (directory);
|
||||
if (dir)
|
||||
{
|
||||
while ((entry = readdir (dir)))
|
||||
{
|
||||
if (hidden_files || (entry->d_name[0] != '.'))
|
||||
{
|
||||
snprintf (complete_filename, sizeof (complete_filename),
|
||||
"%s/%s", directory, entry->d_name);
|
||||
lstat (complete_filename, &statbuf);
|
||||
if (S_ISDIR(statbuf.st_mode))
|
||||
{
|
||||
if (recurse_subdirs
|
||||
&& (strcmp (entry->d_name, ".") != 0)
|
||||
&& (strcmp (entry->d_name, "..") != 0))
|
||||
{
|
||||
dir_exec_on_files (complete_filename, 1, hidden_files,
|
||||
callback, callback_data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*callback) (callback_data, complete_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir (dir);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Searches for the full name of a WeeChat library with name and extension
|
||||
* (searches first in WeeChat user's dir, then WeeChat global lib directory).
|
||||
*
|
||||
* Returns name of library found, NULL if not found.
|
||||
*
|
||||
* Note: result must be freed after use (if not NULL).
|
||||
*/
|
||||
|
||||
char *
|
||||
dir_search_full_lib_name_ext (const char *filename, const char *extension,
|
||||
const char *plugins_dir)
|
||||
{
|
||||
char *name_with_ext, *final_name, *extra_libdir;
|
||||
int length;
|
||||
struct stat st;
|
||||
|
||||
length = strlen (filename) + strlen (extension) + 1;
|
||||
name_with_ext = malloc (length);
|
||||
if (!name_with_ext)
|
||||
return NULL;
|
||||
snprintf (name_with_ext, length,
|
||||
"%s%s",
|
||||
filename,
|
||||
(strchr (filename, '.')) ? "" : extension);
|
||||
|
||||
/* try libdir from environment variable WEECHAT_EXTRA_LIBDIR */
|
||||
extra_libdir = getenv (WEECHAT_EXTRA_LIBDIR);
|
||||
if (extra_libdir && extra_libdir[0])
|
||||
{
|
||||
length = strlen (extra_libdir) + strlen (name_with_ext) +
|
||||
strlen (plugins_dir) + 16;
|
||||
final_name = malloc (length);
|
||||
if (!final_name)
|
||||
{
|
||||
free (name_with_ext);
|
||||
return NULL;
|
||||
}
|
||||
snprintf (final_name, length,
|
||||
"%s%s%s%s%s",
|
||||
extra_libdir,
|
||||
DIR_SEPARATOR,
|
||||
plugins_dir,
|
||||
DIR_SEPARATOR,
|
||||
name_with_ext);
|
||||
if ((stat (final_name, &st) == 0) && (st.st_size > 0))
|
||||
{
|
||||
free (name_with_ext);
|
||||
return final_name;
|
||||
}
|
||||
free (final_name);
|
||||
}
|
||||
|
||||
/* try WeeChat user's dir */
|
||||
length = strlen (weechat_data_dir) + strlen (name_with_ext) +
|
||||
strlen (plugins_dir) + 16;
|
||||
final_name = malloc (length);
|
||||
if (!final_name)
|
||||
{
|
||||
free (name_with_ext);
|
||||
return NULL;
|
||||
}
|
||||
snprintf (final_name, length,
|
||||
"%s%s%s%s%s",
|
||||
weechat_data_dir,
|
||||
DIR_SEPARATOR,
|
||||
plugins_dir,
|
||||
DIR_SEPARATOR,
|
||||
name_with_ext);
|
||||
if ((stat (final_name, &st) == 0) && (st.st_size > 0))
|
||||
{
|
||||
free (name_with_ext);
|
||||
return final_name;
|
||||
}
|
||||
free (final_name);
|
||||
|
||||
/* try WeeChat global lib dir */
|
||||
length = strlen (WEECHAT_LIBDIR) + strlen (name_with_ext) +
|
||||
strlen (plugins_dir) + 16;
|
||||
final_name = malloc (length);
|
||||
if (!final_name)
|
||||
{
|
||||
free (name_with_ext);
|
||||
return NULL;
|
||||
}
|
||||
snprintf (final_name, length,
|
||||
"%s%s%s%s%s",
|
||||
WEECHAT_LIBDIR,
|
||||
DIR_SEPARATOR,
|
||||
plugins_dir,
|
||||
DIR_SEPARATOR,
|
||||
name_with_ext);
|
||||
if ((stat (final_name, &st) == 0) && (st.st_size > 0))
|
||||
{
|
||||
free (name_with_ext);
|
||||
return final_name;
|
||||
}
|
||||
free (final_name);
|
||||
|
||||
free (name_with_ext);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Searches for the full name of a WeeChat library with name.
|
||||
*
|
||||
* All extensions listed in option "weechat.plugin.extension" are tested.
|
||||
*
|
||||
* Note: result must be freed after use (if not NULL).
|
||||
*/
|
||||
|
||||
char *
|
||||
dir_search_full_lib_name (const char *filename, const char *plugins_dir)
|
||||
{
|
||||
char *filename2, *full_name;
|
||||
int i;
|
||||
|
||||
/* expand home in filename */
|
||||
filename2 = string_expand_home (filename);
|
||||
if (!filename2)
|
||||
return NULL;
|
||||
|
||||
/* if full path, return it */
|
||||
if (strchr (filename2, '/') || strchr (filename2, '\\'))
|
||||
return filename2;
|
||||
|
||||
if (config_plugin_extensions)
|
||||
{
|
||||
for (i = 0; i < config_num_plugin_extensions; i++)
|
||||
{
|
||||
full_name = dir_search_full_lib_name_ext (
|
||||
filename2,
|
||||
config_plugin_extensions[i],
|
||||
plugins_dir);
|
||||
if (full_name)
|
||||
{
|
||||
free (filename2);
|
||||
return full_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
full_name = dir_search_full_lib_name_ext (filename2, "", plugins_dir);
|
||||
if (full_name)
|
||||
{
|
||||
free (filename2);
|
||||
return full_name;
|
||||
}
|
||||
}
|
||||
|
||||
free (filename2);
|
||||
|
||||
return strdup (filename);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads content of a file.
|
||||
*
|
||||
* Returns an allocated buffer with the content of file, NULL if error.
|
||||
*
|
||||
* Note: result must be freed after use.
|
||||
*/
|
||||
|
||||
char *
|
||||
dir_file_get_content (const char *filename)
|
||||
{
|
||||
char *buffer, *buffer2;
|
||||
FILE *f;
|
||||
size_t count, fp;
|
||||
|
||||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
buffer = NULL;
|
||||
fp = 0;
|
||||
|
||||
f = fopen (filename, "r");
|
||||
if (!f)
|
||||
goto error;
|
||||
|
||||
while (!feof (f))
|
||||
{
|
||||
if (fp > SIZE_MAX - (1024 * sizeof (char)))
|
||||
goto error;
|
||||
buffer2 = (char *) realloc (buffer, (fp + (1024 * sizeof (char))));
|
||||
if (!buffer2)
|
||||
goto error;
|
||||
buffer = buffer2;
|
||||
count = fread (&buffer[fp], sizeof (char), 1024, f);
|
||||
if (count <= 0)
|
||||
goto error;
|
||||
fp += count;
|
||||
}
|
||||
if (fp > SIZE_MAX - sizeof (char))
|
||||
goto error;
|
||||
buffer2 = (char *) realloc (buffer, fp + sizeof (char));
|
||||
if (!buffer2)
|
||||
goto error;
|
||||
buffer = buffer2;
|
||||
buffer[fp] = '\0';
|
||||
fclose (f);
|
||||
|
||||
return buffer;
|
||||
|
||||
error:
|
||||
if (buffer)
|
||||
free (buffer);
|
||||
if (f)
|
||||
fclose (f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a file to another location.
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
dir_file_copy (const char *from, const char *to)
|
||||
{
|
||||
FILE *src, *dst;
|
||||
char *buffer;
|
||||
int rc;
|
||||
size_t count;
|
||||
|
||||
rc = 0;
|
||||
buffer = NULL;
|
||||
src = NULL;
|
||||
dst = NULL;
|
||||
|
||||
if (!from || !from[0] || !to || !to[0])
|
||||
goto end;
|
||||
|
||||
buffer = malloc (65536);
|
||||
if (!buffer)
|
||||
goto end;
|
||||
|
||||
src = fopen (from, "rb");
|
||||
if (!src)
|
||||
goto end;
|
||||
dst = fopen (to, "wb");
|
||||
if (!dst)
|
||||
goto end;
|
||||
|
||||
while (!feof (src))
|
||||
{
|
||||
count = fread (buffer, 1, 65536, src);
|
||||
if (count <= 0)
|
||||
goto end;
|
||||
if (fwrite (buffer, 1, count, dst) <= 0)
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
|
||||
end:
|
||||
if (buffer)
|
||||
free (buffer);
|
||||
if (src)
|
||||
fclose (src);
|
||||
if (dst)
|
||||
fclose (dst);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compresses a file with gzip.
|
||||
*
|
||||
* The output file must not exist.
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
dir_file_compress_gzip (const char *from, const char *to,
|
||||
int compression_level)
|
||||
{
|
||||
FILE *source, *dest;
|
||||
z_stream strm;
|
||||
unsigned char *buffer_in, *buffer_out;
|
||||
int rc, ret, flush;
|
||||
size_t buffer_size, have;
|
||||
|
||||
source = NULL;
|
||||
dest = NULL;
|
||||
buffer_size = 256 * 1024;
|
||||
buffer_in = NULL;
|
||||
buffer_out = NULL;
|
||||
rc = 0;
|
||||
|
||||
if (!from || !to || (compression_level < 1) || (compression_level > 9))
|
||||
goto end;
|
||||
|
||||
if (access (to, F_OK) == 0)
|
||||
goto end;
|
||||
|
||||
buffer_in = malloc (buffer_size);
|
||||
if (!buffer_in)
|
||||
goto end;
|
||||
buffer_out = malloc (buffer_size);
|
||||
if (!buffer_out)
|
||||
goto end;
|
||||
|
||||
source = fopen (from, "rb");
|
||||
if (!source)
|
||||
goto end;
|
||||
dest = fopen (to, "wb");
|
||||
if (!dest)
|
||||
goto end;
|
||||
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
|
||||
ret = deflateInit2 (
|
||||
&strm,
|
||||
compression_level,
|
||||
Z_DEFLATED, /* method */
|
||||
15 + 16, /* + 16 = gzip instead of zlib */
|
||||
8, /* memLevel */
|
||||
Z_DEFAULT_STRATEGY); /* strategy */
|
||||
if (ret != Z_OK)
|
||||
goto end;
|
||||
|
||||
do
|
||||
{
|
||||
strm.avail_in = fread (buffer_in, 1, buffer_size, source);
|
||||
if (ferror (source))
|
||||
goto error;
|
||||
|
||||
flush = feof (source) ? Z_FINISH : Z_NO_FLUSH;
|
||||
strm.next_in = buffer_in;
|
||||
|
||||
do
|
||||
{
|
||||
strm.avail_out = buffer_size;
|
||||
strm.next_out = buffer_out;
|
||||
ret = deflate (&strm, flush);
|
||||
if (ret == Z_STREAM_ERROR)
|
||||
goto error;
|
||||
have = buffer_size - strm.avail_out;
|
||||
if (fwrite (buffer_out, 1, have, dest) != have || ferror (dest))
|
||||
goto error;
|
||||
} while (strm.avail_out == 0);
|
||||
if (strm.avail_in != 0)
|
||||
goto error;
|
||||
} while (flush != Z_FINISH);
|
||||
|
||||
if (ret != Z_STREAM_END)
|
||||
goto error;
|
||||
|
||||
(void) deflateEnd (&strm);
|
||||
|
||||
rc = 1;
|
||||
goto end;
|
||||
|
||||
error:
|
||||
(void) deflateEnd (&strm);
|
||||
unlink (to);
|
||||
|
||||
end:
|
||||
if (buffer_in)
|
||||
free (buffer_in);
|
||||
if (buffer_out)
|
||||
free (buffer_out);
|
||||
if (source)
|
||||
fclose (source);
|
||||
if (dest)
|
||||
fclose (dest);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compresses a file with zstandard.
|
||||
*
|
||||
* The output file must not exist.
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
dir_file_compress_zstd (const char *from, const char *to,
|
||||
int compression_level)
|
||||
{
|
||||
FILE *source, *dest;
|
||||
void *buffer_in, *buffer_out;
|
||||
size_t buffer_in_size, buffer_out_size, num_read, remaining;
|
||||
int rc, finished, last_chunk;
|
||||
ZSTD_CCtx *cctx;
|
||||
ZSTD_EndDirective mode;
|
||||
ZSTD_inBuffer input;
|
||||
ZSTD_outBuffer output;
|
||||
|
||||
source = NULL;
|
||||
dest = NULL;
|
||||
buffer_in = NULL;
|
||||
buffer_out = NULL;
|
||||
cctx = NULL;
|
||||
rc = 0;
|
||||
|
||||
if (!from || !to || (compression_level < 1) || (compression_level > 19))
|
||||
goto end;
|
||||
|
||||
if (access (to, F_OK) == 0)
|
||||
goto end;
|
||||
|
||||
buffer_in_size = ZSTD_CStreamInSize ();
|
||||
buffer_in = malloc (buffer_in_size);
|
||||
if (!buffer_in)
|
||||
goto end;
|
||||
buffer_out_size = ZSTD_CStreamOutSize ();
|
||||
buffer_out = malloc (buffer_out_size);
|
||||
if (!buffer_out)
|
||||
goto end;
|
||||
|
||||
source = fopen (from, "rb");
|
||||
if (!source)
|
||||
goto end;
|
||||
dest = fopen (to, "wb");
|
||||
if (!dest)
|
||||
goto end;
|
||||
|
||||
cctx = ZSTD_createCCtx ();
|
||||
if (!cctx)
|
||||
goto end;
|
||||
|
||||
ZSTD_CCtx_setParameter (cctx, ZSTD_c_compressionLevel, compression_level);
|
||||
|
||||
while (1)
|
||||
{
|
||||
num_read = fread (buffer_in, 1, buffer_in_size, source);
|
||||
if (ferror (source))
|
||||
goto error;
|
||||
last_chunk = (num_read < buffer_in_size);
|
||||
mode = (last_chunk) ? ZSTD_e_end : ZSTD_e_continue;
|
||||
input.src = buffer_in;
|
||||
input.size = num_read;
|
||||
input.pos = 0;
|
||||
finished = 0;
|
||||
while (!finished)
|
||||
{
|
||||
output.dst = buffer_out;
|
||||
output.size = buffer_out_size;
|
||||
output.pos = 0;
|
||||
remaining = ZSTD_compressStream2(cctx, &output , &input, mode);
|
||||
if (ZSTD_isError (remaining))
|
||||
goto error;
|
||||
fwrite (buffer_out, 1, output.pos, dest);
|
||||
finished = (last_chunk) ? (remaining == 0) : (input.pos == input.size);
|
||||
};
|
||||
if (input.pos != input.size)
|
||||
goto error;
|
||||
if (last_chunk)
|
||||
break;
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
goto end;
|
||||
|
||||
error:
|
||||
if (cctx)
|
||||
{
|
||||
ZSTD_freeCCtx (cctx);
|
||||
cctx = NULL;
|
||||
}
|
||||
unlink (to);
|
||||
|
||||
end:
|
||||
if (cctx)
|
||||
ZSTD_freeCCtx (cctx);
|
||||
if (buffer_in)
|
||||
free (buffer_in);
|
||||
if (buffer_out)
|
||||
free (buffer_out);
|
||||
if (source)
|
||||
fclose (source);
|
||||
if (dest)
|
||||
fclose (dest);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compresses a file with gzip or zstandard.
|
||||
*
|
||||
* The output file must not exist.
|
||||
*
|
||||
* Supported values for parameter "compressor":
|
||||
* - "gzip": gzip compression (via zlib)
|
||||
* - "zstd": zstandard compression
|
||||
*
|
||||
* Parameter "compression_level" is the compression level as percentage:
|
||||
* from 1 (fast, low compression) to 100 (slow, best compression).
|
||||
*
|
||||
* Returns:
|
||||
* 1: OK
|
||||
* 0: error
|
||||
*/
|
||||
|
||||
int
|
||||
dir_file_compress (const char *filename_input,
|
||||
const char *filename_output,
|
||||
const char *compressor,
|
||||
int compression_level)
|
||||
{
|
||||
int level;
|
||||
|
||||
if (!compressor || (compression_level < 1) || (compression_level > 100))
|
||||
return 0;
|
||||
|
||||
if (strcmp (compressor, "gzip") == 0)
|
||||
{
|
||||
/* convert percent to zlib compression level (1-9) */
|
||||
level = (((compression_level - 1) * 9) / 100) + 1;
|
||||
return dir_file_compress_gzip (filename_input, filename_output, level);
|
||||
}
|
||||
else if (strcmp (compressor, "zstd") == 0)
|
||||
{
|
||||
/* convert percent to zstd compression level (1-19) */
|
||||
level = (((compression_level - 1) * 19) / 100) + 1;
|
||||
return dir_file_compress_zstd (filename_input, filename_output, level);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -25,6 +25,9 @@ extern int dir_mkdir_home (const char *directory, int mode);
|
||||
extern int dir_mkdir (const char *directory, int mode);
|
||||
extern int dir_mkdir_parents (const char *directory, int mode);
|
||||
extern int dir_rmtree (const char *directory);
|
||||
extern void dir_create_home_dirs ();
|
||||
extern void dir_remove_home_dirs ();
|
||||
extern char *dir_get_string_home_dirs ();
|
||||
extern void dir_exec_on_files (const char *directory, int recurse_subdirs,
|
||||
int hidden_files,
|
||||
void (*callback)(void *data,
|
||||
@@ -34,8 +37,7 @@ extern char *dir_search_full_lib_name (const char *filename,
|
||||
const char *sys_directory);
|
||||
extern char *dir_file_get_content (const char *filename);
|
||||
extern int dir_file_copy (const char *from, const char *to);
|
||||
extern void dir_create_home_dirs ();
|
||||
extern void dir_remove_home_dirs ();
|
||||
extern char *dir_get_string_home_dirs ();
|
||||
extern int dir_file_compress (const char *from, const char *to,
|
||||
const char *compressor, int compression_level);
|
||||
|
||||
#endif /* WEECHAT_DIR_H */
|
||||
|
||||
@@ -47,6 +47,9 @@ list(APPEND EXTRA_LIBS "m")
|
||||
|
||||
list(APPEND EXTRA_LIBS ${CURL_LIBRARIES})
|
||||
|
||||
list(APPEND EXTRA_LIBS ${ZLIB_LIBRARY})
|
||||
list(APPEND EXTRA_LIBS ${LIBZSTD_LDFLAGS})
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
# link with resolv lib on macOS
|
||||
list(APPEND EXTRA_LIBS "resolv")
|
||||
|
||||
@@ -48,6 +48,8 @@ weechat_headless_LDADD = ./../../../core/lib_weechat_core.a \
|
||||
$(GCRYPT_LFLAGS) \
|
||||
$(GNUTLS_LFLAGS) \
|
||||
$(CURL_LFLAGS) \
|
||||
$(ZLIB_LFLAGS) \
|
||||
$(ZSTD_LFLAGS) \
|
||||
-lm
|
||||
|
||||
weechat_headless_SOURCES = main.c
|
||||
|
||||
@@ -45,6 +45,8 @@ weechat_LDADD = ./../../../core/lib_weechat_core.a \
|
||||
$(GCRYPT_LFLAGS) \
|
||||
$(GNUTLS_LFLAGS) \
|
||||
$(CURL_LFLAGS) \
|
||||
$(ZLIB_LFLAGS) \
|
||||
$(ZSTD_LFLAGS) \
|
||||
-lm
|
||||
|
||||
weechat_SOURCES = main.c
|
||||
|
||||
@@ -676,6 +676,7 @@ plugin_load (const char *filename, int init_plugin, int argc, char **argv)
|
||||
new_plugin->exec_on_files = &dir_exec_on_files;
|
||||
new_plugin->file_get_content = &dir_file_get_content;
|
||||
new_plugin->file_copy = &dir_file_copy;
|
||||
new_plugin->file_compress = &dir_file_compress;
|
||||
|
||||
new_plugin->util_timeval_cmp = &util_timeval_cmp;
|
||||
new_plugin->util_timeval_diff = &util_timeval_diff;
|
||||
|
||||
@@ -68,7 +68,7 @@ struct timeval;
|
||||
* please change the date with current one; for a second change at same
|
||||
* date, increment the 01, otherwise please keep 01.
|
||||
*/
|
||||
#define WEECHAT_PLUGIN_API_VERSION "20220925-01"
|
||||
#define WEECHAT_PLUGIN_API_VERSION "20220926-01"
|
||||
|
||||
/* macros for defining plugin infos */
|
||||
#define WEECHAT_PLUGIN_NAME(__name) \
|
||||
@@ -402,6 +402,8 @@ struct t_weechat_plugin
|
||||
void *callback_data);
|
||||
char *(*file_get_content) (const char *filename);
|
||||
int (*file_copy) (const char *from, const char *to);
|
||||
int (*file_compress) (const char *from, const char *to,
|
||||
const char *compressor, int compression_level);
|
||||
|
||||
/* util */
|
||||
int (*util_timeval_cmp) (struct timeval *tv1, struct timeval *tv2);
|
||||
@@ -1415,6 +1417,10 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin);
|
||||
(weechat_plugin->file_get_content)(__filename)
|
||||
#define weechat_file_copy(__from, __to) \
|
||||
(weechat_plugin->file_copy)(__from, __to)
|
||||
#define weechat_file_compress(__from, __to, __compressor, \
|
||||
__compression_level) \
|
||||
(weechat_plugin->file_compress)(__from, __to, __compressor, \
|
||||
__compression_level)
|
||||
|
||||
/* util */
|
||||
#define weechat_util_timeval_cmp(__time1, __time2) \
|
||||
|
||||
@@ -137,6 +137,8 @@ target_link_libraries(tests
|
||||
weechat_core
|
||||
${EXTRA_LIBS}
|
||||
${CURL_LIBRARIES}
|
||||
${ZLIB_LIBRARY}
|
||||
${LIBZSTD_LDFLAGS}
|
||||
${CPPUTEST_LIBRARIES}
|
||||
-rdynamic
|
||||
)
|
||||
|
||||
@@ -66,6 +66,8 @@ tests_LDADD = ./../src/core/lib_weechat_core.a \
|
||||
$(GCRYPT_LFLAGS) \
|
||||
$(GNUTLS_LFLAGS) \
|
||||
$(CURL_LFLAGS) \
|
||||
$(ZLIB_LFLAGS) \
|
||||
$(ZSTD_LFLAGS) \
|
||||
$(CPPUTEST_LFLAGS) \
|
||||
-lm
|
||||
tests_LDFLAGS = -rdynamic
|
||||
|
||||
Reference in New Issue
Block a user