diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b3e0dfa --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/far2l"] + path = vendor/far2l + url = https://github.com/VPROFi/far2l.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ca0cf3d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0.2) + +project(processes) + +#set(CMAKE_BUILD_TYPE Debug) +set(CMAKE_BUILD_TYPE Release) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_C_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# build far2l +add_subdirectory(vendor/far2l) + +# build plugin +set(PROJECT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/vendor/far2l) +get_directory_property(INSTALL_DIR DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION INSTALL_DIR) + +add_subdirectory(src) diff --git a/README.md b/README.md new file mode 100644 index 0000000..b485e80 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# processplugin + +TODO: +Плагин только умеет выводить процессы, и удалять их. Нужно расширять. + +Плагин позволяет (linux и macos): + * просматривать, редактировать информацию о процессах + +The plugin allows (linux and macos): + * view and edit information about processes, ... + +Build instruction like far2l (https://github.com/VPROFi/far2l) + +If your want build inside other version far2l - put content ./src into ./far2l/processes and add to ./far2l/CMakeLists.txt add_subdirectory (processes) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..8965753 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.0.2) + +project(processes) + +get_directory_property(PROJECT_SOURCE_DIR DIRECTORY ../ DEFINITION PROJECT_SOURCE_DIR) +get_directory_property(INSTALL_DIR DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION INSTALL_DIR) + +message("processes PROJECT_SOURCE_DIR ${PROJECT_SOURCE_DIR} ${CMAKE_SYSTEM_NAME}") + +set(SOURCES +farconnect.cpp +fardialog.cpp +farpanel.cpp +plugincfg.cpp +plugin.cpp +farapi.cpp +progress.cpp +procplugin.cpp +procpanel.cpp +process/process.cpp +process/processes.cpp +common/errname.c +common/log.c +common/sizestr.c +common/utf8util.c +common/procutil.c +) + + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_C_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") + +# GCC 6+ has a warning for an ABI change due to a bug introduced in GCC 5: +# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=77728. As we are building all of +# drcachesim and not linking to other C++ code, we can just ignore it. +if (ARM AND CMAKE_COMPILER_IS_GNUCC) + include(CheckCXXCompilerFlag) + CHECK_CXX_COMPILER_FLAG(-Wno-psabi GCC_HAS_NO_PSABI) + if (GCC_HAS_NO_PSABI) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-psabi") + endif (GCC_HAS_NO_PSABI) +endif () + +add_library(processes MODULE ${SOURCES}) +target_link_libraries(processes utils far2l) + +target_compile_definitions(processes PRIVATE -DUSEUCD=OFF -DWINPORT_DIRECT -DUNICODE -DFAR_DONT_USE_INTERNALS) + +target_include_directories(processes PRIVATE .) +target_include_directories(processes PRIVATE ./process) +target_include_directories(processes PRIVATE ${PROJECT_SOURCE_DIR}/utils/include) +target_include_directories(processes PRIVATE ${PROJECT_SOURCE_DIR}/far2l/far2sdk) +target_include_directories(processes PRIVATE ${PROJECT_SOURCE_DIR}/far2l/Include) +target_include_directories(processes PRIVATE ${PROJECT_SOURCE_DIR}/WinPort) + +set_target_properties(processes + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${INSTALL_DIR}/Plugins/processes/plug" + PREFIX "" + SUFFIX ".far-plug-wide") + +add_custom_command(TARGET processes POST_BUILD + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/configs + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/configs "${INSTALL_DIR}/Plugins/processes" +) diff --git a/src/common/errname.c b/src/common/errname.c new file mode 100644 index 0000000..bfbf168 --- /dev/null +++ b/src/common/errname.c @@ -0,0 +1,325 @@ +#include + +// for duplicates +#if !defined(__APPLE__) && !defined(__FreeBSD__) +#define _EWOULDBLOCK 41 /* Operation would block */ +#define _EDEADLOCK 58 + +#ifndef ENOKEY +#define ENOKEY 126 /* Required key not available */ +#define EKEYEXPIRED 127 /* Key has expired */ +#define EKEYREVOKED 128 /* Key has been revoked */ +#define EKEYREJECTED 129 /* Key was rejected by service */ +#define EOWNERDEAD 130 /* Owner died */ +#define ENOTRECOVERABLE 131 /* State not recoverable */ +#define ERFKILL 132 /* Operation not possible due to RF-kill */ +#define EHWPOISON 133 /* Memory page has hardware error */ +#endif + +#endif + +#define CASE_ERR(err) \ + case err: return #err + +static const char *itoa(int i) { + static char buf[12]; + char *ptr = buf + sizeof(buf) - 1; + unsigned int u; + int minus = 0; + if (i < 0) { + minus = 1; + u = ((unsigned int)(-(1+i))) + 1; + } else + u = i; + *ptr = 0; + do { + *--ptr = '0' + (u % 10); + } while(u/=10); + + if (minus) + *--ptr = '-'; + return ptr; +} + +#ifdef __cplusplus +extern "C" { +#endif + +const char * errorname(int err) +{ + switch (err) { + case 0: return "SUCCESS"; +#if !defined(__APPLE__) && !defined(__FreeBSD__) + CASE_ERR(EPERM );/* Operation not permitted */ + CASE_ERR(ENOENT );/* No such file or directory */ + CASE_ERR(ESRCH );/* No such process */ + CASE_ERR(EINTR );/* Interrupted system call */ + CASE_ERR(EIO );/* I/O error */ + CASE_ERR(ENXIO );/* No such device or address */ + CASE_ERR(E2BIG );/* Argument list too long */ + CASE_ERR(ENOEXEC );/* Exec format error */ + CASE_ERR(EBADF );/* Bad file number */ + CASE_ERR(ECHILD );/* No child processes */ + CASE_ERR(EAGAIN );/* Try again */ + CASE_ERR(ENOMEM );/* Out of memory */ + CASE_ERR(EACCES );/* Permission denied */ + CASE_ERR(EFAULT );/* Bad address */ + CASE_ERR(ENOTBLK );/* Block device required */ + CASE_ERR(EBUSY );/* Device or resource busy */ + CASE_ERR(EEXIST );/* File exists */ + CASE_ERR(EXDEV );/* Cross-device link */ + CASE_ERR(ENODEV );/* No such device */ + CASE_ERR(ENOTDIR );/* Not a directory */ + CASE_ERR(EISDIR );/* Is a directory */ + CASE_ERR(EINVAL );/* Invalid argument */ + CASE_ERR(ENFILE );/* File table overflow */ + CASE_ERR(EMFILE );/* Too many open files */ + CASE_ERR(ENOTTY );/* Not a typewriter */ + CASE_ERR(ETXTBSY );/* Text file busy */ + CASE_ERR(EFBIG );/* File too large */ + CASE_ERR(ENOSPC );/* No space left on device */ + CASE_ERR(ESPIPE );/* Illegal seek */ + CASE_ERR(EROFS );/* Read-only file system */ + CASE_ERR(EMLINK );/* Too many links */ + CASE_ERR(EPIPE );/* Broken pipe */ + CASE_ERR(EDOM );/* Math argument out of domain of func */ + CASE_ERR(ERANGE );/* Math result not representable */ + CASE_ERR(EDEADLK );/* Resource deadlock would occur */ + CASE_ERR(ENAMETOOLONG );/* File name too long */ + CASE_ERR(ENOLCK );/* No record locks available */ + CASE_ERR(ENOSYS );/* Invalid system call number */ + CASE_ERR(ENOTEMPTY );/* Directory not empty */ + CASE_ERR(ELOOP );/* Too many symbolic links encountered */ +#if ELNRNG != 41 + CASE_ERR(_EWOULDBLOCK );/* Operation would block */ +#endif + CASE_ERR(ENOMSG );/* No message of desired type */ + CASE_ERR(EIDRM );/* Identifier removed */ + CASE_ERR(ECHRNG );/* Channel number out of range */ + CASE_ERR(EL2NSYNC );/* Level 2 not synchronized */ + CASE_ERR(EL3HLT );/* Level 3 halted */ + CASE_ERR(EL3RST );/* Level 3 reset */ + CASE_ERR(ELNRNG );/* Link number out of range */ + CASE_ERR(EUNATCH );/* Protocol driver not attached */ + CASE_ERR(ENOCSI );/* No CSI structure available */ + CASE_ERR(EL2HLT );/* Level 2 halted */ + CASE_ERR(EBADE );/* Invalid exchange */ + CASE_ERR(EBADR );/* Invalid request descriptor */ + CASE_ERR(EXFULL );/* Exchange full */ + CASE_ERR(ENOANO );/* No anode */ + CASE_ERR(EBADRQC );/* Invalid request code */ + CASE_ERR(EBADSLT );/* Invalid slot */ + CASE_ERR(_EDEADLOCK );/* Resource deadlock would occur */ + CASE_ERR(EBFONT );/* Bad font file format */ + CASE_ERR(ENOSTR );/* Device not a stream */ + CASE_ERR(ENODATA );/* No data available */ + CASE_ERR(ETIME );/* Timer expired */ + CASE_ERR(ENOSR );/* Out of streams resources */ + CASE_ERR(ENONET );/* Machine is not on the network */ + CASE_ERR(ENOPKG );/* Package not installed */ + CASE_ERR(EREMOTE );/* Object is remote */ + CASE_ERR(ENOLINK );/* Link has been severed */ + CASE_ERR(EADV );/* Advertise error */ + CASE_ERR(ESRMNT );/* Srmount error */ + CASE_ERR(ECOMM );/* Communication error on send */ + CASE_ERR(EPROTO );/* Protocol error */ + CASE_ERR(EMULTIHOP );/* Multihop attempted */ + CASE_ERR(EDOTDOT );/* RFS specific error */ + CASE_ERR(EBADMSG );/* Not a data message */ + CASE_ERR(EOVERFLOW );/* Value too large for defined data type */ + CASE_ERR(ENOTUNIQ );/* Name not unique on network */ + CASE_ERR(EBADFD );/* File descriptor in bad state */ + CASE_ERR(EREMCHG );/* Remote address changed */ + CASE_ERR(ELIBACC );/* Can not access a needed shared library */ + CASE_ERR(ELIBBAD );/* Accessing a corrupted shared library */ + CASE_ERR(ELIBSCN );/* .lib section in a.out corrupted */ + CASE_ERR(ELIBMAX );/* Attempting to link in too many shared libraries */ + CASE_ERR(ELIBEXEC );/* Cannot exec a shared library directly */ + CASE_ERR(EILSEQ );/* Illegal byte sequence */ + CASE_ERR(ERESTART );/* Interrupted system call should be restarted */ + CASE_ERR(ESTRPIPE );/* Streams pipe error */ + CASE_ERR(EUSERS );/* Too many users */ + CASE_ERR(ENOTSOCK );/* Socket operation on non-socket */ + CASE_ERR(EDESTADDRREQ );/* Destination address required */ + CASE_ERR(EMSGSIZE );/* Message too long */ + CASE_ERR(EPROTOTYPE );/* Protocol wrong type for socket */ + CASE_ERR(ENOPROTOOPT );/* Protocol not available */ + CASE_ERR(EPROTONOSUPPORT);/* Protocol not supported */ + CASE_ERR(ESOCKTNOSUPPORT);/* Socket type not supported */ + CASE_ERR(EOPNOTSUPP );/* Operation not supported on transport endpoint */ + CASE_ERR(EPFNOSUPPORT );/* Protocol family not supported */ + CASE_ERR(EAFNOSUPPORT );/* Address family not supported by protocol */ + CASE_ERR(EADDRINUSE );/* Address already in use */ + CASE_ERR(EADDRNOTAVAIL );/* Cannot assign requested address */ + CASE_ERR(ENETDOWN );/* Network is down */ + CASE_ERR(ENETUNREACH );/* Network is unreachable */ + CASE_ERR(ENETRESET );/* Network dropped connection because of reset */ + CASE_ERR(ECONNABORTED );/* Software caused connection abort */ + CASE_ERR(ECONNRESET );/* Connection reset by peer */ + CASE_ERR(ENOBUFS );/* No buffer space available */ + CASE_ERR(EISCONN );/* Transport endpoint is already connected */ + CASE_ERR(ENOTCONN );/* Transport endpoint is not connected */ + CASE_ERR(ESHUTDOWN );/* Cannot send after transport endpoint shutdown */ + CASE_ERR(ETOOMANYREFS );/* Too many references: cannot splice */ + CASE_ERR(ETIMEDOUT );/* Connection timed out */ + CASE_ERR(ECONNREFUSED );/* Connection refused */ + CASE_ERR(EHOSTDOWN );/* Host is down */ + CASE_ERR(EHOSTUNREACH );/* No route to host */ + CASE_ERR(EALREADY );/* Operation already in progress */ + CASE_ERR(EINPROGRESS );/* Operation now in progress */ + CASE_ERR(ESTALE );/* Stale file handle */ + CASE_ERR(EUCLEAN );/* Structure needs cleaning */ + CASE_ERR(ENOTNAM );/* Not a XENIX named type file */ + CASE_ERR(ENAVAIL );/* No XENIX semaphores available */ + CASE_ERR(EISNAM );/* Is a named type file */ + CASE_ERR(EREMOTEIO );/* Remote I/O error */ + CASE_ERR(EDQUOT );/* Quota exceeded */ + CASE_ERR(ENOMEDIUM );/* No medium found */ + CASE_ERR(EMEDIUMTYPE );/* Wrong medium type */ + CASE_ERR(ECANCELED );/* Operation Canceled */ +#if EADDRNOTAVAIL != ENOKEY + CASE_ERR(ENOKEY );/* Required key not available */ + CASE_ERR(EKEYEXPIRED );/* Key has expired */ + CASE_ERR(EKEYREVOKED );/* Key has been revoked */ + CASE_ERR(EKEYREJECTED );/* Key was rejected by service */ + CASE_ERR(EOWNERDEAD );/* Owner died */ + CASE_ERR(ENOTRECOVERABLE);/* State not recoverable */ + CASE_ERR(ERFKILL );/* Operation not possible due to RF-kill */ + CASE_ERR(EHWPOISON );/* Memory page has hardware error */ +#endif + +#else + CASE_ERR(EPERM );/* Operation not permitted */ + CASE_ERR(ENOENT );/* No such file or directory */ + CASE_ERR(ESRCH );/* No such process */ + CASE_ERR(EINTR );/* Interrupted system call */ + CASE_ERR(EIO );/* Input/output error */ + CASE_ERR(ENXIO );/* Device not configured */ + CASE_ERR(E2BIG );/* Argument list too long */ + CASE_ERR(ENOEXEC );/* Exec format error */ + CASE_ERR(EBADF );/* Bad file descriptor */ + CASE_ERR(ECHILD );/* No child processes */ + CASE_ERR(EDEADLK );/* Resource deadlock avoided */ + CASE_ERR(ENOMEM );/* Cannot allocate memory */ + CASE_ERR(EACCES );/* Permission denied */ + CASE_ERR(EFAULT );/* Bad address */ + CASE_ERR(ENOTBLK );/* Block device required */ + CASE_ERR(EBUSY );/* Device / Resource busy */ + CASE_ERR(EEXIST );/* File exists */ + CASE_ERR(EXDEV );/* Cross-device link */ + CASE_ERR(ENODEV );/* Operation not supported by device */ + CASE_ERR(ENOTDIR );/* Not a directory */ + CASE_ERR(EISDIR );/* Is a directory */ + CASE_ERR(EINVAL );/* Invalid argument */ + CASE_ERR(ENFILE );/* Too many open files in system */ + CASE_ERR(EMFILE );/* Too many open files */ + CASE_ERR(ENOTTY );/* Inappropriate ioctl for device */ + CASE_ERR(ETXTBSY );/* Text file busy */ + CASE_ERR(EFBIG );/* File too large */ + CASE_ERR(ENOSPC );/* No space left on device */ + CASE_ERR(ESPIPE );/* Illegal seek */ + CASE_ERR(EROFS );/* Read-only file system */ + CASE_ERR(EMLINK );/* Too many links */ + CASE_ERR(EPIPE );/* Broken pipe */ + CASE_ERR(EDOM );/* Numerical argument out of domain */ + CASE_ERR(ERANGE );/* Result too large */ + CASE_ERR(EAGAIN );/* Resource temporarily unavailable */ + CASE_ERR(EINPROGRESS );/* Operation now in progress */ + CASE_ERR(EALREADY );/* Operation already in progress */ + CASE_ERR(ENOTSOCK );/* Socket operation on non-socket */ + CASE_ERR(EDESTADDRREQ );/* Destination address required */ + CASE_ERR(EMSGSIZE );/* Message too long */ + CASE_ERR(EPROTOTYPE );/* Protocol wrong type for socket */ + CASE_ERR(ENOPROTOOPT );/* Protocol not available */ + CASE_ERR(EPROTONOSUPPORT);/* Protocol not supported */ + CASE_ERR(ESOCKTNOSUPPORT);/* Socket type not supported */ + CASE_ERR(ENOTSUP );/* Operation not supported */ + CASE_ERR(EPFNOSUPPORT );/* Protocol family not supported */ + CASE_ERR(EAFNOSUPPORT );/* Address family not supported by protocol family */ + CASE_ERR(EADDRINUSE );/* Address already in use */ + CASE_ERR(EADDRNOTAVAIL );/* Can't assign requested address */ + CASE_ERR(ENETDOWN );/* Network is down */ + CASE_ERR(ENETUNREACH );/* Network is unreachable */ + CASE_ERR(ENETRESET );/* Network dropped connection on reset */ + CASE_ERR(ECONNABORTED );/* Software caused connection abort */ + CASE_ERR(ECONNRESET );/* Connection reset by peer */ + CASE_ERR(ENOBUFS );/* No buffer space available */ + CASE_ERR(EISCONN );/* Socket is already connected */ + CASE_ERR(ENOTCONN );/* Socket is not connected */ + CASE_ERR(ESHUTDOWN );/* Can't send after socket shutdown */ + CASE_ERR(ETOOMANYREFS );/* Too many references: can't splice */ + CASE_ERR(ETIMEDOUT );/* Operation timed out */ + CASE_ERR(ECONNREFUSED );/* Connection refused */ + CASE_ERR(ELOOP );/* Too many levels of symbolic links */ + CASE_ERR(ENAMETOOLONG );/* File name too long */ + CASE_ERR(EHOSTDOWN );/* Host is down */ + CASE_ERR(EHOSTUNREACH );/* No route to host */ + CASE_ERR(ENOTEMPTY );/* Directory not empty */ + CASE_ERR(EPROCLIM );/* Too many processes */ + CASE_ERR(EUSERS );/* Too many users */ + CASE_ERR(EDQUOT );/* Disc quota exceeded */ + CASE_ERR(ESTALE );/* Stale NFS file handle */ + CASE_ERR(EREMOTE );/* Too many levels of remote in path */ + CASE_ERR(EBADRPC );/* RPC struct is bad */ + CASE_ERR(ERPCMISMATCH );/* RPC version wrong */ + CASE_ERR(EPROGUNAVAIL );/* RPC prog. not avail */ + CASE_ERR(EPROGMISMATCH );/* Program version wrong */ + CASE_ERR(EPROCUNAVAIL );/* Bad procedure for program */ + CASE_ERR(ENOLCK );/* No locks available */ + CASE_ERR(ENOSYS );/* Function not implemented */ + CASE_ERR(EFTYPE );/* Inappropriate file type or format */ + CASE_ERR(EAUTH );/* Authentication error */ + CASE_ERR(ENEEDAUTH );/* Need authenticator */ + CASE_ERR(EPWROFF );/* Device power is off */ + CASE_ERR(EDEVERR );/* Device error, e.g. paper out */ + CASE_ERR(EOVERFLOW );/* Value too large to be stored in data type */ + CASE_ERR(EBADEXEC );/* Bad executable */ + CASE_ERR(EBADARCH );/* Bad CPU type in executable */ + CASE_ERR(ESHLIBVERS );/* Shared library version mismatch */ + CASE_ERR(EBADMACHO );/* Malformed Macho file */ + CASE_ERR(ECANCELED );/* Operation canceled */ + CASE_ERR(EIDRM );/* Identifier removed */ + CASE_ERR(ENOMSG );/* No message of desired type */ + CASE_ERR(EILSEQ );/* Illegal byte sequence */ + CASE_ERR(ENOATTR );/* Attribute not found */ + CASE_ERR(EBADMSG );/* Bad message */ + CASE_ERR(EMULTIHOP );/* Reserved */ + CASE_ERR(ENODATA );/* No message available on STREAM */ + CASE_ERR(ENOLINK );/* Reserved */ + CASE_ERR(ENOSR );/* No STREAM resources */ + CASE_ERR(ENOSTR );/* Not a STREAM */ + CASE_ERR(EPROTO );/* Protocol error */ + CASE_ERR(ETIME );/* STREAM ioctl timeout */ + CASE_ERR(EOPNOTSUPP );/* Operation not supported on socket */ + CASE_ERR(ENOPOLICY );/* No such policy registered */ + CASE_ERR(ENOTRECOVERABLE);/* State not recoverable */ + CASE_ERR(EOWNERDEAD );/* Previous owner died */ + CASE_ERR(EQFULL );/* Interface output queue is full */ +#endif + default: + return itoa(err); + } +} + +#ifdef __cplusplus +} +#endif + + +#ifdef MAIN_COMMON_ERRNAME + +#include "log.h" + +#define LOG_FILE "" +#define LOG_SOURCE_FILE "errname.c" + +int main(int argc, char * argv[]) +{ + LOG_ERROR_CONSOLE("%u (%s)\n", 0, errorname(0)); + LOG_ERROR_CONSOLE("%u (%s)\n", EPERM, errorname(EPERM)); + LOG_ERROR_CONSOLE("%u (%s)\n", ENOENT, errorname(ENOENT)); + LOG_ERROR_CONSOLE("%u (%s)\n", EOWNERDEAD, errorname(EOWNERDEAD)); + LOG_ERROR_CONSOLE("%u (%s)\n", 33333, errorname(33333)); + return 0; +} +#endif // MAIN_COMMON_ERRNAME diff --git a/src/common/errname.h b/src/common/errname.h new file mode 100644 index 0000000..602ea91 --- /dev/null +++ b/src/common/errname.h @@ -0,0 +1,14 @@ +#if !defined(COMMON__ERRNAME) +#define COMMON__ERRNAME + +#ifdef __cplusplus +extern "C" { +#endif + +const char * errorname(int err); + +#ifdef __cplusplus +} +#endif + +#endif // COMMON__ERRNAME diff --git a/src/common/log.c b/src/common/log.c new file mode 100644 index 0000000..a7278d5 --- /dev/null +++ b/src/common/log.c @@ -0,0 +1,46 @@ +#include "log.h" + +#include +#include +#include + +#include + +extern void common_log(const char * filename, const char * prefix, const char * file, const char *function, unsigned int line, const char *format, ...) +{ + va_list args; + const char out_format[] = "%s %s:%u %s %s%s"; + char *xformat = (char *)alloca(strlen(prefix) + strlen(file) + strlen(format) + strlen(function) + sizeof(out_format)); + sprintf(xformat, out_format, prefix, file, line, function, (*format != '\n') ? " - " : "", format); + + FILE *stream = 0; + if( filename && filename[0] ) + stream = fopen(filename, "at"); + + if( !stream ) + stream = stderr; + + va_start(args, format); + vfprintf(stream, xformat, args); + va_end(args); + + if( stream != stderr ) + fclose(stream); +} + +#ifdef MAIN_COMMON_LOG + +#define LOG_FILE "/tmp/log.log" +#define LOG_SOURCE_FILE "log.c" + +int main(int argc, char * argv[]) +{ + LOG_INFO("\n"); + LOG_WARN("\n"); + LOG_ERROR("\n"); + LOG_INFO_CONSOLE("\n"); + LOG_WARN_CONSOLE("\n"); + LOG_ERROR_CONSOLE("\n"); + return 0; +} +#endif // MAIN_COMMON_LOG diff --git a/src/common/log.h b/src/common/log.h new file mode 100644 index 0000000..58598b7 --- /dev/null +++ b/src/common/log.h @@ -0,0 +1,25 @@ +#ifndef __COMMON_LOG_H__ +#define __COMMON_LOG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +void common_log(const char * filename, const char * prefix, const char * file, const char *function, unsigned int line, const char *format, ...); + +#ifdef __cplusplus +} +#endif + +// LOG_FILE and LOG_SOURCE_FILE define in c(cpp) file +// use '#define LOG_FILE ""' for console output + +#define LOG_INFO(args...) common_log(LOG_FILE, "[info] ", LOG_SOURCE_FILE, __FUNCTION__, __LINE__, args) +#define LOG_WARN(args...) common_log(LOG_FILE, "[warn] ", LOG_SOURCE_FILE, __FUNCTION__, __LINE__, args) +#define LOG_ERROR(args...) common_log(LOG_FILE, "[error]", LOG_SOURCE_FILE, __FUNCTION__, __LINE__, args) + +#define LOG_INFO_CONSOLE(args...) common_log(0, "[info] ", LOG_SOURCE_FILE, __FUNCTION__, __LINE__, args) +#define LOG_WARN_CONSOLE(args...) common_log(0, "[warn] ", LOG_SOURCE_FILE, __FUNCTION__, __LINE__, args) +#define LOG_ERROR_CONSOLE(args...) common_log(0, "[error]", LOG_SOURCE_FILE, __FUNCTION__, __LINE__, args) + +#endif // __COMMON_LOG_H__ diff --git a/src/common/procutil.c b/src/common/procutil.c new file mode 100644 index 0000000..47b4264 --- /dev/null +++ b/src/common/procutil.c @@ -0,0 +1,274 @@ +#include "procutil.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "errname.h" +#include "log.h" + +#define LOG_SOURCE_FILE "fileutil.c" + +#ifdef MAIN_COMMON_PROCUTIL +const char * LOG_FILE = ""; +#else +extern const char * LOG_FILE; +#endif + +#if INTPTR_MAX == INT32_MAX +#define LLFMT "%lld" +#elif INTPTR_MAX == INT64_MAX +#define LLFMT "%ld" +#else + #error "Environment not 32 or 64-bit." +#endif + +void FreeFileData(char * buf) +{ + free((void *)buf); +} + +char * GetFileData(const char * path, ssize_t *readed) +{ + #define buffGRW 1024 + size_t size = buffGRW; + ssize_t tot_read = 0; + + char * buf = (char *)malloc(size); + if( !buf ) { + LOG_ERROR("malloc(" LLFMT ") ... error (%s)\n", size, errorname(errno)); + return 0; + } + + do { + ssize_t cur_read; + int fd = open(path, O_RDONLY, 0); + if( -1 == fd ) { + LOG_ERROR("open(%s) ... error (%s)\n", path, errorname(errno)); + free((void *)buf); + buf = 0; + break; + } + + while( (cur_read = read(fd, buf + tot_read, size - tot_read)) > 0 ) { + tot_read += cur_read; + if( tot_read < size ) break; + buf = (char *)realloc(buf, (size += buffGRW)); + if( !buf ) { + LOG_ERROR("malloc(" LLFMT ") ... error (%s)\n", size, errorname(errno)); + break; + } + }; + + close(fd); + + if( !buf ) + break; + + if( tot_read < 1 ) { + LOG_ERROR("read(%s) ... error (%s)\n", path, errorname(errno)); + free((void *)buf); + buf = 0; + break; + } + + buf[tot_read] = '\0'; + if( readed ) + *readed = tot_read; + + } while(0); + #undef buffGRW + + return buf; +} + +unsigned int GetExistingCPUs(void) +{ + DIR * cpu = opendir("/sys/devices/system/cpu"); + unsigned int existingCPUs = 0; + if( cpu ) { + const struct dirent* entry; + while( (entry = readdir(cpu) ) != NULL) { + + if( entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN) + continue; + + if( memcmp(entry->d_name, "cpu", 3) == 0 ) { + char* endp; + unsigned long int id = strtoul(entry->d_name + 3, &endp, 10); + if( id == ULONG_MAX || endp == entry->d_name + 3 || *endp != '\0') + continue; + existingCPUs++; + } + }; + } + closedir(cpu); + return existingCPUs ? existingCPUs:1; +} + +unsigned int GetActiveCPUs(unsigned int existingCPUs) +{ + unsigned int i = 0, activeCPUs = 0; + if( existingCPUs == 0 ) + existingCPUs = GetExistingCPUs(); + for( i=0; i < existingCPUs; i++ ) { + char path[sizeof("/sys/devices/system/cpu/cpu4294967296/online")]; + if( snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/online", i) < 0 ) { + LOG_ERROR("snprintf(fmt=\"/sys/devices/system/cpu/cpu%d/online\") ... error (%s)\n", i, errorname(errno)); + continue; + } else { + struct stat sbuf; + if( stat(path, &sbuf) < 0 ) + activeCPUs++; + else { + char * buf = GetFileData(path, 0); + if( !buf || buf[0] != '0' ) + activeCPUs++; + FreeFileData(buf); + } + } + } + return activeCPUs ? activeCPUs:1; +} + +/* This subtraction is used by Linux / NetBSD / OpenBSD for calculation of CPU usage items. */ +static inline unsigned long long saturatingSub(unsigned long long a, unsigned long long b) { + return a > b ? a - b : 0; +} + +#ifndef PROC_LINE_LENGTH +#define PROC_LINE_LENGTH 4096 +#endif + +void GetCPUTimes(CPUTimes *ct) +{ + char buffer[PROC_LINE_LENGTH + 1]; + FILE* file = fopen("/proc/stat", "r"); + CPUTimes prev_ct = *ct; + if( !file ) { + LOG_ERROR("fopen(\"/proc/stat\", \"r\") ... error (%s)\n", errorname(errno)); + return; + } + + if( !fgets(buffer, sizeof(buffer), file) || + memcmp(buffer, "cpu", 3) != 0 ) { + LOG_ERROR("can`t process \"/proc/stat\" file\n"); + fclose(file); + return; + } + + memset(ct, 0, sizeof(CPUTimes)); + + ct->existingCPUs = GetExistingCPUs(); + ct->activeCPUs = GetActiveCPUs(ct->existingCPUs); + ct->period = 0.0F; + + (void)sscanf(buffer, "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", + &ct->user, + &ct->nice, + &ct->system, + &ct->idle, + &ct->iowait, + &ct->irq, + &ct->softirq, + &ct->steal, + &ct->guest, + &ct->guest_nice); + + // Guest time is already accounted in usertime + ct->user -= ct->guest; + ct->nice -= ct->guest_nice; + + // Fields existing on kernels >= 2.6 + // (and RHEL's patched kernel 2.4...) + ct->idleall = ct->idle + ct->iowait; + ct->systemall = ct->system + ct->irq + ct->softirq; + ct->virtall = ct->guest + ct->guest_nice; + ct->total = ct->user + ct->nice + ct->systemall + ct->idleall + ct->steal + ct->virtall; + +// if( prev_ct.user | prev_ct.system | prev_ct.idle ) { + // Since we do a subtraction (usertime - guest) and cputime64_to_clock_t() + // used in /proc/stat rounds down numbers, it can lead to a case where the + // integer overflow. + ct->user_period = saturatingSub(ct->user, prev_ct.user); + ct->nice_period = saturatingSub(ct->nice, prev_ct.nice); + ct->system_period = saturatingSub(ct->system, prev_ct.system); + ct->systemall_period = saturatingSub(ct->systemall, prev_ct.systemall); + ct->idleall_period = saturatingSub(ct->idleall, prev_ct.idleall); + ct->idle_period = saturatingSub(ct->idle, prev_ct.idle); + ct->iowait_period = saturatingSub(ct->iowait, prev_ct.iowait); + ct->irq_period = saturatingSub(ct->irq, prev_ct.irq); + ct->softirq_period = saturatingSub(ct->softirq, prev_ct.softirq); + ct->steal_period = saturatingSub(ct->steal, prev_ct.steal); + ct->guest_period = saturatingSub(ct->virtall, prev_ct.guest); + ct->total_period = saturatingSub(ct->total, prev_ct.total); + assert( ct->activeCPUs >= 1 ); + ct->period = ((double)ct->total_period) / (double)ct->activeCPUs; +// } + + while( fgets(buffer, sizeof(buffer), file) ) { + if( memcmp(buffer, "procs_running", 3) != 0 ) { + ct->runningTasks = strtoul(buffer + strlen("procs_running"), NULL, 10); + break; + } + } + + fclose(file); + + LOG_INFO("user : %lld\n", ct->user ); + LOG_INFO("nice : %lld\n", ct->nice ); + LOG_INFO("system : %lld\n", ct->system ); + LOG_INFO("idle : %lld\n", ct->idle ); + LOG_INFO("iowait : %lld\n", ct->iowait ); + LOG_INFO("irq : %lld\n", ct->irq ); + LOG_INFO("softirq : %lld\n", ct->softirq ); + LOG_INFO("steal : %lld\n", ct->steal ); + LOG_INFO("guest : %lld\n", ct->guest ); + LOG_INFO("guest_nice : %lld\n", ct->guest_nice ); + LOG_INFO("user_period : %lld\n", ct->user_period ); + LOG_INFO("nice_period : %lld\n", ct->nice_period ); + LOG_INFO("system_period : %lld\n", ct->system_period ); + LOG_INFO("systemall_period : %lld\n", ct->systemall_period ); + LOG_INFO("idleall_period : %lld\n", ct->idleall_period ); + LOG_INFO("idle_period : %lld\n", ct->idle_period ); + LOG_INFO("iowait_period : %lld\n", ct->iowait_period ); + LOG_INFO("irq_period : %lld\n", ct->irq_period ); + LOG_INFO("softirq_period : %lld\n", ct->softirq_period ); + LOG_INFO("steal_period : %lld\n", ct->steal_period ); + LOG_INFO("guest_period : %lld\n", ct->guest_period ); + LOG_INFO("total_period : %lld\n", ct->total_period ); + LOG_INFO("period : %f\n", ct->period ); + LOG_INFO("runningTasks : %d\n", ct->runningTasks ); + LOG_INFO("activeCPUs : %d\n", ct->activeCPUs ); + LOG_INFO("existingCPUs : %d\n", ct->existingCPUs ); + + return; +} + +#ifdef MAIN_COMMON_PROCUTIL + +int main(int argc, char * argv[]) +{ + CPUTimes ct = {0}; + ssize_t readed; + char * buf = GetFileData("/proc/self/stat", &readed); + if( buf ) { + LOG_INFO("/proc/self/stat %s", buf); + FreeFileData(buf); + } + + LOG_INFO("existingCPUs: %d\n", GetExistingCPUs()); + LOG_INFO("activeCPUs: %d\n", GetActiveCPUs(0)); + GetCPUTimes(&ct); + + return 0; +} + +#endif //MAIN_COMMON_PROCUTIL diff --git a/src/common/procutil.h b/src/common/procutil.h new file mode 100644 index 0000000..76cf2e5 --- /dev/null +++ b/src/common/procutil.h @@ -0,0 +1,62 @@ +#ifndef __COMMON_PROCUTIL_H__ +#define __COMMON_PROCUTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +char * GetFileData(const char * path, ssize_t *readed); +void FreeFileData(char * buf); + +unsigned int GetExistingCPUs(void); +unsigned int GetActiveCPUs(unsigned int existingCPUs); + +typedef struct { + unsigned long long user; + unsigned long long nice; + unsigned long long system; + unsigned long long idle; + unsigned long long iowait; + unsigned long long irq; + unsigned long long softirq; + unsigned long long steal; + unsigned long long guest; + unsigned long long guest_nice; + + unsigned long long idleall; + unsigned long long systemall; + unsigned long long virtall; + unsigned long long total; + + unsigned long long user_period; + unsigned long long nice_period; + unsigned long long system_period; + unsigned long long idle_period; + + unsigned long long iowait_period; + unsigned long long irq_period; + unsigned long long softirq_period; + unsigned long long steal_period; + unsigned long long guest_period; + + unsigned long long systemall_period; + unsigned long long idleall_period; + unsigned long long total_period; + + unsigned int activeCPUs; + unsigned int existingCPUs; + unsigned int runningTasks; + + double period; + +} CPUTimes; + +void GetCPUTimes(CPUTimes *ct); + +#ifdef __cplusplus +} +#endif + +#endif // __COMMON_PROCUTIL_H__ diff --git a/src/common/sizestr.c b/src/common/sizestr.c new file mode 100644 index 0000000..0ca7953 --- /dev/null +++ b/src/common/sizestr.c @@ -0,0 +1,103 @@ +#include "sizestr.h" +#include +#include +#include + +#if INTPTR_MAX == INT32_MAX +#define LLFMT "%llu" +#elif INTPTR_MAX == INT64_MAX +#define LLFMT "%lu" +#else + #error "Environment not 32 or 64-bit." +#endif + +extern const char * size_to_str(unsigned long long size) +{ + static const char * units[] = { + "B", + "Kb", + "Mb", + "Gb", + "Tb", + "Eb", + "Zb" + }; + static char buf[sizeof("3.1415926535897932384626433832795028841971693993751058209749445923078 Zb")] = {0}; + int offset = 0; + long double print_size = size; + while( (size/1024) && (print_size = print_size/1024.0) && (size = size/1024) && ++offset ); + + if( offset && snprintf(buf, sizeof(buf), "%.3Lg %s", print_size, units[offset]) > 0 ) + return buf; + + if( snprintf(buf, sizeof(buf), "%llu %s", size, units[offset]) > 0 ) + return buf; + + return "ERROR"; + +} + +const char * msec_to_str(uint64_t msec) +{ + static char buf[sizeof("213503982334 days 24 hours 60 min 999 sec 999 ms")] = {0}; + const static struct { + const char * fmt; + uint64_t divider; + } prtime[] = { + {LLFMT " days ", 86400000}, + {LLFMT " hours ", 3600000}, + {LLFMT " min ", 60000}, + {LLFMT " sec ", 1000}, + {LLFMT " ms", 1} + }; + int i, offset = 0; + + buf[0] = 0; + for( i=0; i < sizeof(prtime)/sizeof(prtime[0]); i++ ) { + if( offset >= 0 && (msec / prtime[i].divider) ) { + offset += snprintf(buf + offset, + sizeof(buf) - offset, + prtime[i].fmt, + msec/prtime[i].divider); + msec = msec % prtime[i].divider; + } + } + return buf; +} + +#ifdef MAIN_COMMON_SIZESTR + +#define LOG_FILE "/tmp/log.log" +#define LOG_SOURCE_FILE "log.c" + +#include "log.h" + +int main(int argc, char * argv[]) +{ + uint64_t num = (uint64_t)-1; + long double numf = 3.0; + LOG_INFO_CONSOLE("sizeof(unsigned long long) %u sizeof(double) %u sizeof(long double) %u sizeof(size_t) %u\n", sizeof(unsigned long long), sizeof(double), sizeof(long double), sizeof(size_t)); + LOG_INFO_CONSOLE("\"%llu\"\n", num); + LOG_INFO_CONSOLE("\"%.100Lf\"\n", numf/7.0); + LOG_INFO_CONSOLE("\"%.100Le\"\n", numf/7.0); + LOG_INFO_CONSOLE("%s\n", size_to_str(0)); + LOG_INFO_CONSOLE("%s\n", size_to_str(1000)); + LOG_INFO_CONSOLE("%s\n", size_to_str(1024)); + LOG_INFO_CONSOLE("%s\n", size_to_str(1024*1024)); + LOG_INFO_CONSOLE("%s\n", size_to_str(1024*1024*1024)); + LOG_INFO_CONSOLE("%s\n", size_to_str(100000000000ull)); + LOG_INFO_CONSOLE("%s\n", size_to_str(17792387055516ull)); + LOG_INFO_CONSOLE("%s\n", size_to_str((1024ull)*1024*1024*1024)); + LOG_INFO_CONSOLE("%s\n", size_to_str((1024ull)*1024*1024*1024*1024)); + LOG_INFO_CONSOLE("%s\n", size_to_str(18446744073709551615ull)); + + LOG_INFO_CONSOLE("%s\n", msec_to_str(101)); + LOG_INFO_CONSOLE("%s\n", msec_to_str(1000)); + LOG_INFO_CONSOLE("%s\n", msec_to_str(100001)); + LOG_INFO_CONSOLE("%s\n", msec_to_str(10000002)); + LOG_INFO_CONSOLE("%s\n", msec_to_str(100000000003ull)); + LOG_INFO_CONSOLE("%s\n", msec_to_str(17792387055516ull)); + LOG_INFO_CONSOLE("%s\n", msec_to_str(18446744073709551615ull)); + return 0; +} +#endif // MAIN_COMMON_SIZESTR diff --git a/src/common/sizestr.h b/src/common/sizestr.h new file mode 100644 index 0000000..1497a33 --- /dev/null +++ b/src/common/sizestr.h @@ -0,0 +1,19 @@ +#ifndef __COMMON_SIZESTR_H__ +#define __COMMON_SIZESTR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern const char * size_to_str(unsigned long long size); +extern const char * msec_to_str(uint64_t msec); + +#define SEC_TO_MS(sec) (((uint64_t)sec)*1000) + +#ifdef __cplusplus +} +#endif + +#endif // __COMMON_SIZESTR_H__ diff --git a/src/common/utf8util.c b/src/common/utf8util.c new file mode 100644 index 0000000..6148042 --- /dev/null +++ b/src/common/utf8util.c @@ -0,0 +1,1732 @@ +#include "utf8util.h" +#include + +char* StrToLwrExt(char* _pString) +{ +unsigned char* pString = (unsigned char*)_pString; +unsigned char* p = pString; +unsigned char* pExtChar = 0; + +if (pString && *pString) { + while (*p) { + if ((*p >= 0x41) && (*p <= 0x5a)) /* US ASCII */ + (*p) += 0x20; + else if (*p > 0xc0) { + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xc3: /* Latin 1 */ + if ((*p >= 0x80) + && (*p <= 0x9e) + && (*p != 0x97)) + (*p) += 0x20; /* US ASCII shift */ + break; + case 0xc4: /* Latin ext */ + if (((*p >= 0x80) + && (*p <= 0xb7) + && (*p != 0xb0)) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + else if ((*p >= 0xb9) + && (*p <= 0xbe) + && (*p % 2)) /* Odd */ + (*p)++; /* Next char is lwr */ + else if (*p == 0xbf) { + *pExtChar = 0xc5; + (*p) = 0x80; + } + break; + case 0xc5: /* Latin ext */ + if ((*p >= 0x81) + && (*p <= 0x88) + && (*p % 2)) /* Odd */ + (*p)++; /* Next char is lwr */ + else if ((*p >= 0x8a) + && (*p <= 0xb7) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + else if (*p == 0xb8) { + *pExtChar = 0xc3; + (*p) = 0xbf; + } + else if ((*p >= 0xb9) + && (*p <= 0xbe) + && (*p % 2)) /* Odd */ + (*p)++; /* Next char is lwr */ + break; + case 0xc6: /* Latin ext */ + switch (*p) { + case 0x81: + *pExtChar = 0xc9; + (*p) = 0x93; + break; + case 0x86: + *pExtChar = 0xc9; + (*p) = 0x94; + break; + case 0x89: + *pExtChar = 0xc9; + (*p) = 0x96; + break; + case 0x8a: + *pExtChar = 0xc9; + (*p) = 0x97; + break; + case 0x8e: + *pExtChar = 0xc9; + (*p) = 0x98; + break; + case 0x8f: + *pExtChar = 0xc9; + (*p) = 0x99; + break; + case 0x90: + *pExtChar = 0xc9; + (*p) = 0x9b; + break; + case 0x93: + *pExtChar = 0xc9; + (*p) = 0xa0; + break; + case 0x94: + *pExtChar = 0xc9; + (*p) = 0xa3; + break; + case 0x96: + *pExtChar = 0xc9; + (*p) = 0xa9; + break; + case 0x97: + *pExtChar = 0xc9; + (*p) = 0xa8; + break; + case 0x9c: + *pExtChar = 0xc9; + (*p) = 0xaf; + break; + case 0x9d: + *pExtChar = 0xc9; + (*p) = 0xb2; + break; + case 0x9f: + *pExtChar = 0xc9; + (*p) = 0xb5; + break; + case 0xa9: + *pExtChar = 0xca; + (*p) = 0x83; + break; + case 0xae: + *pExtChar = 0xca; + (*p) = 0x88; + break; + case 0xb1: + *pExtChar = 0xca; + (*p) = 0x8a; + break; + case 0xb2: + *pExtChar = 0xca; + (*p) = 0x8b; + break; + case 0xb7: + *pExtChar = 0xca; + (*p) = 0x92; + break; + case 0x82: + case 0x84: + case 0x87: + case 0x8b: + case 0x91: + case 0x98: + case 0xa0: + case 0xa2: + case 0xa4: + case 0xa7: + case 0xac: + case 0xaf: + case 0xb3: + case 0xb5: + case 0xb8: + case 0xbc: + (*p)++; /* Next char is lwr */ + break; + default: + break; + } + break; + case 0xc7: /* Latin ext */ + if (*p == 0x84) + (*p) = 0x86; + else if (*p == 0x85) + (*p)++; /* Next char is lwr */ + else if (*p == 0x87) + (*p) = 0x89; + else if (*p == 0x88) + (*p)++; /* Next char is lwr */ + else if (*p == 0x8a) + (*p) = 0x8c; + else if (*p == 0x8b) + (*p)++; /* Next char is lwr */ + else if ((*p >= 0x8d) + && (*p <= 0x9c) + && (*p % 2)) /* Odd */ + (*p)++; /* Next char is lwr */ + else if ((*p >= 0x9e) + && (*p <= 0xaf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + else if (*p == 0xb1) + (*p) = 0xb3; + else if (*p == 0xb2) + (*p)++; /* Next char is lwr */ + else if (*p == 0xb4) + (*p)++; /* Next char is lwr */ + else if (*p == 0xb6) { + *pExtChar = 0xc6; + (*p) = 0x95; + } + else if (*p == 0xb7) { + *pExtChar = 0xc6; + (*p) = 0xbf; + } + else if ((*p >= 0xb8) + && (*p <= 0xbf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0xc8: /* Latin ext */ + if ((*p >= 0x80) + && (*p <= 0x9f) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + else if (*p == 0xa0) { + *pExtChar = 0xc6; + (*p) = 0x9e; + } + else if ((*p >= 0xa2) + && (*p <= 0xb3) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + else if (*p == 0xbb) + (*p)++; /* Next char is lwr */ + else if (*p == 0xbd) { + *pExtChar = 0xc6; + (*p) = 0x9a; + } + /* 0xba three byte small 0xe2 0xb1 0xa5 */ + /* 0xbe three byte small 0xe2 0xb1 0xa6 */ + break; + case 0xc9: /* Latin ext */ + if (*p == 0x81) + (*p)++; /* Next char is lwr */ + else if (*p == 0x83) { + *pExtChar = 0xc6; + (*p) = 0x80; + } + else if (*p == 0x84) { + *pExtChar = 0xca; + (*p) = 0x89; + } + else if (*p == 0x85) { + *pExtChar = 0xca; + (*p) = 0x8c; + } + else if ((*p >= 0x86) + && (*p <= 0x8f) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0xcd: /* Greek & Coptic */ + switch (*p) { + case 0xb0: + case 0xb2: + case 0xb6: + (*p)++; /* Next char is lwr */ + break; + case 0xbf: + *pExtChar = 0xcf; + (*p) = 0xb3; + break; + default: + break; + } + break; + case 0xce: /* Greek & Coptic */ + if (*p == 0x86) + (*p) = 0xac; + else if (*p == 0x88) + (*p) = 0xad; + else if (*p == 0x89) + (*p) = 0xae; + else if (*p == 0x8a) + (*p) = 0xaf; + else if (*p == 0x8c) { + *pExtChar = 0xcf; + (*p) = 0x8c; + } + else if (*p == 0x8e) { + *pExtChar = 0xcf; + (*p) = 0x8d; + } + else if (*p == 0x8f) { + *pExtChar = 0xcf; + (*p) = 0x8e; + } + else if ((*p >= 0x91) + && (*p <= 0x9f)) + (*p) += 0x20; /* US ASCII shift */ + else if ((*p >= 0xa0) + && (*p <= 0xab) + && (*p != 0xa2)) { + *pExtChar = 0xcf; + (*p) -= 0x20; + } + break; + case 0xcf: /* Greek & Coptic */ + if (*p == 0x8f) + (*p) = 0x97; + else if ((*p >= 0x98) + && (*p <= 0xaf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + else if (*p == 0xb4) { + (*p) = 0x91; + } + else if (*p == 0xb7) + (*p)++; /* Next char is lwr */ + else if (*p == 0xb9) + (*p) = 0xb2; + else if (*p == 0xba) + (*p)++; /* Next char is lwr */ + else if (*p == 0xbd) { + *pExtChar = 0xcd; + (*p) = 0xbb; + } + else if (*p == 0xbe) { + *pExtChar = 0xcd; + (*p) = 0xbc; + } + else if (*p == 0xbf) { + *pExtChar = 0xcd; + (*p) = 0xbd; + } + break; + case 0xd0: /* Cyrillic */ + if ((*p >= 0x80) + && (*p <= 0x8f)) { + *pExtChar = 0xd1; + (*p) += 0x10; + } + else if ((*p >= 0x90) + && (*p <= 0x9f)) + (*p) += 0x20; /* US ASCII shift */ + else if ((*p >= 0xa0) + && (*p <= 0xaf)) { + *pExtChar = 0xd1; + (*p) -= 0x20; + } + break; + case 0xd1: /* Cyrillic supplement */ + if ((*p >= 0xa0) + && (*p <= 0xbf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0xd2: /* Cyrillic supplement */ + if (*p == 0x80) + (*p)++; /* Next char is lwr */ + else if ((*p >= 0x8a) + && (*p <= 0xbf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0xd3: /* Cyrillic supplement */ + if (*p == 0x80) + (*p) = 0x8f; + else if ((*p >= 0x81) + && (*p <= 0x8e) + && (*p % 2)) /* Odd */ + (*p)++; /* Next char is lwr */ + else if ((*p >= 0x90) + && (*p <= 0xbf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0xd4: /* Cyrillic supplement & Armenian */ + if ((*p >= 0x80) + && (*p <= 0xaf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + else if ((*p >= 0xb1) + && (*p <= 0xbf)) { + *pExtChar = 0xd5; + (*p) -= 0x10; + } + break; + case 0xd5: /* Armenian */ + if ((*p >= 0x80) + && (*p <= 0x8f)) { + (*p) += 0x30; + } + else if ((*p >= 0x90) + && (*p <= 0x96)) { + *pExtChar = 0xd6; + (*p) -= 0x10; + } + break; + case 0xe1: /* Three byte code */ + pExtChar = p; + p++; + switch (*pExtChar) { + case 0x82: /* Georgian asomtavruli */ + if ((*p >= 0xa0) + && (*p <= 0xbf)) { + *pExtChar = 0x83; + (*p) -= 0x10; + } + break; + case 0x83: /* Georgian asomtavruli */ + if (((*p >= 0x80) + && (*p <= 0x85)) + || (*p == 0x87) + || (*p == 0x8d)) + (*p) += 0x30; + break; + case 0x8e: /* Cherokee */ + if ((*p >= 0xa0) + && (*p <= 0xaf)) { + *(p - 2) = 0xea; + *pExtChar = 0xad; + (*p) += 0x10; + } + else if ((*p >= 0xb0) + && (*p <= 0xbf)) { + *(p - 2) = 0xea; + *pExtChar = 0xae; + (*p) -= 0x30; + } + break; + case 0x8f: /* Cherokee */ + if ((*p >= 0x80) + && (*p <= 0xaf)) { + *(p - 2) = 0xea; + *pExtChar = 0xae; + (*p) += 0x10; + } + else if ((*p >= 0xb0) + && (*p <= 0xb5)) { + (*p) += 0x08; + } + /* 0xbe three byte small 0xe2 0xb1 0xa6 */ + break; + case 0xb2: /* Georgian mtavruli */ + if (((*p >= 0x90) + && (*p <= 0xba)) + || (*p == 0xbd) + || (*p == 0xbe) + || (*p == 0xbf)) + *pExtChar = 0x83; + break; + case 0xb8: /* Latin ext */ + if ((*p >= 0x80) + && (*p <= 0xbf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0xb9: /* Latin ext */ + if ((*p >= 0x80) + && (*p <= 0xbf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0xba: /* Latin ext */ + if ((*p >= 0x80) + && (*p <= 0x94) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + else if ((*p >= 0xa0) + && (*p <= 0xbf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + /* 0x9e Two byte small 0xc3 0x9f */ + break; + case 0xbb: /* Latin ext */ + if ((*p >= 0x80) + && (*p <= 0xbf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0xbc: /* Greek ex */ + if ((*p >= 0x88) + && (*p <= 0x8f)) + (*p) -= 0x08; + else if ((*p >= 0x98) + && (*p <= 0x9d)) + (*p) -= 0x08; + else if ((*p >= 0xa8) + && (*p <= 0xaf)) + (*p) -= 0x08; + else if ((*p >= 0xb8) + && (*p <= 0xbf)) + (*p) -= 0x08; + break; + case 0xbd: /* Greek ex */ + if ((*p >= 0x88) + && (*p <= 0x8d)) + (*p) -= 0x08; + else if ((*p == 0x99) + || (*p == 0x9b) + || (*p == 0x9d) + || (*p == 0x9f)) + (*p) -= 0x08; + else if ((*p >= 0xa8) + && (*p <= 0xaf)) + (*p) -= 0x08; + break; + case 0xbe: /* Greek ex */ + if ((*p >= 0x88) + && (*p <= 0x8f)) + (*p) -= 0x08; + else if ((*p >= 0x98) + && (*p <= 0x9f)) + (*p) -= 0x08; + else if ((*p >= 0xa8) + && (*p <= 0xaf)) + (*p) -= 0x08; + else if ((*p >= 0xb8) + && (*p <= 0xb9)) + (*p) -= 0x08; + else if ((*p >= 0xba) + && (*p <= 0xbb)) { + *(p - 1) = 0xbd; + (*p) -= 0x0a; + } + else if (*p == 0xbc) + (*p) -= 0x09; + break; + case 0xbf: /* Greek ex */ + if ((*p >= 0x88) + && (*p <= 0x8b)) { + *(p - 1) = 0xbd; + (*p) += 0x2a; + } + else if (*p == 0x8c) + (*p) -= 0x09; + else if ((*p >= 0x98) + && (*p <= 0x99)) + (*p) -= 0x08; + else if ((*p >= 0x9a) + && (*p <= 0x9b)) { + *(p - 1) = 0xbd; + (*p) += 0x1c; + } + else if ((*p >= 0xa8) + && (*p <= 0xa9)) + (*p) -= 0x08; + else if ((*p >= 0xaa) + && (*p <= 0xab)) { + *(p - 1) = 0xbd; + (*p) += 0x10; + } + else if (*p == 0xac) + (*p) -= 0x07; + else if ((*p >= 0xb8) + && (*p <= 0xb9)) { + *(p - 1) = 0xbd; + } + else if ((*p >= 0xba) + && (*p <= 0xbb)) { + *(p - 1) = 0xbd; + (*p) += 0x02; + } + else if (*p == 0xbc) + (*p) -= 0x09; + break; + default: + break; + } + break; + case 0xe2: /* Three byte code */ + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xb0: /* Glagolitic */ + if ((*p >= 0x80) + && (*p <= 0x8f)) { + (*p) += 0x30; + } + else if ((*p >= 0x90) + && (*p <= 0xae)) { + *pExtChar = 0xb1; + (*p) -= 0x10; + } + break; + case 0xb1: /* Latin ext */ + switch (*p) { + case 0xa0: + case 0xa7: + case 0xa9: + case 0xab: + case 0xb2: + case 0xb5: + (*p)++; /* Next char is lwr */ + break; + case 0xa2: /* Two byte small 0xc9 0xab */ + case 0xa4: /* Two byte small 0xc9 0xbd */ + case 0xad: /* Two byte small 0xc9 0x91 */ + case 0xae: /* Two byte small 0xc9 0xb1 */ + case 0xaf: /* Two byte small 0xc9 0x90 */ + case 0xb0: /* Two byte small 0xc9 0x92 */ + case 0xbe: /* Two byte small 0xc8 0xbf */ + case 0xbf: /* Two byte small 0xc9 0x80 */ + break; + case 0xa3: + *(p - 2) = 0xe1; + *(p - 1) = 0xb5; + *(p) = 0xbd; + break; + default: + break; + } + break; + case 0xb2: /* Coptic */ + if ((*p >= 0x80) + && (*p <= 0xbf) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0xb3: /* Coptic */ + if (((*p >= 0x80) + && (*p <= 0xa3) + && (!(*p % 2))) /* Even */ + || (*p == 0xab) + || (*p == 0xad) + || (*p == 0xb2)) + (*p)++; /* Next char is lwr */ + break; + case 0xb4: /* Georgian nuskhuri */ + if (((*p >= 0x80) + && (*p <= 0xa5)) + || (*p == 0xa7) + || (*p == 0xad)) { + *(p - 2) = 0xe1; + *(p - 1) = 0x83; + (*p) += 0x10; + } + break; + default: + break; + } + break; + case 0xea: /* Three byte code */ + pExtChar = p; + p++; + switch (*pExtChar) { + case 0x99: /* Cyrillic */ + if ((*p >= 0x80) + && (*p <= 0xad) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0x9a: /* Cyrillic */ + if ((*p >= 0x80) + && (*p <= 0x9b) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0x9c: /* Latin ext */ + if ((((*p >= 0xa2) + && (*p <= 0xaf)) + || ((*p >= 0xb2) + && (*p <= 0xbf))) + && (!(*p % 2))) /* Even */ + (*p)++; /* Next char is lwr */ + break; + case 0x9d: /* Latin ext */ + if ((((*p >= 0x80) + && (*p <= 0xaf)) + && (!(*p % 2))) /* Even */ + || (*p == 0xb9) + || (*p == 0xbb) + || (*p == 0xbe)) + (*p)++; /* Next char is lwr */ + else if (*p == 0xbd) { + *(p - 2) = 0xe1; + *(p - 1) = 0xb5; + *(p) = 0xb9; + } + break; + case 0x9e: /* Latin ext */ + if (((((*p >= 0x80) + && (*p <= 0x87)) + || ((*p >= 0x96) + && (*p <= 0xa9)) + || ((*p >= 0xb4) + && (*p <= 0xbf))) + && (!(*p % 2))) /* Even */ + || (*p == 0x8b) + || (*p == 0x90) + || (*p == 0x92)) + (*p)++; /* Next char is lwr */ + else if (*p == 0xb3) { + *(p - 2) = 0xea; + *(p - 1) = 0xad; + *(p) = 0x93; + } + /* case 0x8d: // Two byte small 0xc9 0xa5 */ + /* case 0xaa: // Two byte small 0xc9 0xa6 */ + /* case 0xab: // Two byte small 0xc9 0x9c */ + /* case 0xac: // Two byte small 0xc9 0xa1 */ + /* case 0xad: // Two byte small 0xc9 0xac */ + /* case 0xae: // Two byte small 0xc9 0xaa */ + /* case 0xb0: // Two byte small 0xca 0x9e */ + /* case 0xb1: // Two byte small 0xca 0x87 */ + /* case 0xb2: // Two byte small 0xca 0x9d */ + break; + case 0x9f: /* Latin ext */ + if ((*p == 0x82) + || (*p == 0x87) + || (*p == 0x89) + || (*p == 0xb5)) + (*p)++; /* Next char is lwr */ + else if (*p == 0x84) { + *(p - 2) = 0xea; + *(p - 1) = 0x9e; + *(p) = 0x94; + } + else if (*p == 0x86) { + *(p - 2) = 0xe1; + *(p - 1) = 0xb6; + *(p) = 0x8e; + } + /* case 0x85: // Two byte small 0xca 0x82 */ + break; + default: + break; + } + break; + case 0xef: /* Three byte code */ + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xbc: /* Latin fullwidth */ + if ((*p >= 0xa1) + && (*p <= 0xba)) { + *pExtChar = 0xbd; + (*p) -= 0x20; + } + break; + default: + break; + } + break; + case 0xf0: /* Four byte code */ + pExtChar = p; + p++; + switch (*pExtChar) { + case 0x90: + pExtChar = p; + p++; + switch (*pExtChar) { + case 0x90: /* Deseret */ + if ((*p >= 0x80) + && (*p <= 0x97)) { + (*p) += 0x28; + } + else if ((*p >= 0x98) + && (*p <= 0xa7)) { + *pExtChar = 0x91; + (*p) -= 0x18; + } + break; + case 0x92: /* Osage */ + if ((*p >= 0xb0) + && (*p <= 0xbf)) { + *pExtChar = 0x93; + (*p) -= 0x18; + } + break; + case 0x93: /* Osage */ + if ((*p >= 0x80) + && (*p <= 0x93)) + (*p) += 0x28; + break; + case 0xb2: /* Old hungarian */ + if ((*p >= 0x80) + && (*p <= 0xb2)) + *pExtChar = 0xb3; + break; + default: + break; + } + break; + case 0x91: + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xa2: /* Warang citi */ + if ((*p >= 0xa0) + && (*p <= 0xbf)) { + *pExtChar = 0xa3; + (*p) -= 0x20; + } + break; + default: + break; + } + break; + case 0x96: + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xb9: /* Medefaidrin */ + if ((*p >= 0x80) + && (*p <= 0x9f)) { + (*p) += 0x20; + } + break; + default: + break; + } + break; + case 0x9E: + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xA4: /* Adlam */ + if ((*p >= 0x80) + && (*p <= 0x9d)) + (*p) += 0x22; + else if ((*p >= 0x9e) + && (*p <= 0xa1)) { + *(pExtChar) = 0xa5; + (*p) -= 0x1e; + } + break; + default: + break; + } + break; + default: + break; + } + break; + default: + break; + } + pExtChar = 0; + } + p++; + } + } + return _pString; +} +int StrnCiCmp(const char* s1, const char* s2, size_t ztCount) +{ +unsigned char* pStr1Low = 0; +unsigned char* pStr2Low = 0; +unsigned char* p1 = 0; +unsigned char* p2 = 0; + + if (s1 && *s1 && s2 && *s2) { + + pStr1Low = (unsigned char*)calloc(strlen(s1) + 1, sizeof(unsigned char)); + if (pStr1Low) { + pStr2Low = (unsigned char*)calloc(strlen(s2) + 1, sizeof(unsigned char)); + if (pStr2Low) { + p1 = pStr1Low; + p2 = pStr2Low; + strcpy((char*)pStr1Low, s1); + strcpy((char*)pStr2Low, s2); + StrToLwrExt((char *)pStr1Low); + StrToLwrExt((char *)pStr2Low); + for (; ztCount--; p1++, p2++) { + int iDiff = *p1 - *p2; + if (iDiff != 0 || !*p1 || !*p2) { + free(pStr1Low); + free(pStr2Low); + return iDiff; + } + } + free(pStr1Low); + free(pStr2Low); + return 0; + } + free(pStr1Low); + return (-1); + } + return (-1); + } + return (-1); +} +int StrCiCmp(const char* s1, const char* s2) +{ + return StrnCiCmp(s1, s2, (size_t)(-1)); +} +char* StrCiStr(const char* s1, const char* s2) +{ +char* p = (char*)s1; +size_t len = 0; + + if (s1 && *s1 && s2 && *s2) { + len = strlen(s2); + while (*p) { + if (StrnCiCmp(p, s2, len) == 0) + return (char*)p; + p++; + } + } + return (0); +} + +char* StrToUprExt(char* _pString) +{ +unsigned char* pString = (unsigned char*)_pString; +unsigned char* p = pString; +unsigned char* pExtChar = 0; + + if (pString && *pString) { + while (*p) { + if ((*p >= 0x61) && (*p <= 0x7a)) /* US ASCII */ + (*p) -= 0x20; + else if (*p > 0xc0) { + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xc3: /* Latin 1 */ + /* 0x9f Three byte capital 0xe1 0xba 0x9e */ + if ((*p >= 0xa0) + && (*p <= 0xbe) + && (*p != 0xb7)) + (*p) -= 0x20; /* US ASCII shift */ + else if (*p == 0xbf) { + *pExtChar = 0xc5; + (*p) = 0xb8; + } + break; + case 0xc4: /* Latin ext */ + if (((*p >= 0x80) + && (*p <= 0xb7) + && (*p != 0xb1)) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + else if ((*p >= 0xb9) + && (*p <= 0xbe) + && (!(*p % 2))) /* Even */ + (*p)--; /* Prev char is upr */ + break; + case 0xc5: /* Latin ext */ + if (*p == 0x80) { + *pExtChar = 0xc4; + (*p) = 0xbf; + } + else if ((*p >= 0x81) + && (*p <= 0x88) + && (!(*p % 2))) /* Even */ + (*p)--; /* Prev char is upr */ + else if ((*p >= 0x8a) + && (*p <= 0xb7) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + else if (*p == 0xb8) { + *pExtChar = 0xc5; + (*p) = 0xb8; + } + else if ((*p >= 0xb9) + && (*p <= 0xbe) + && (!(*p % 2))) /* Even */ + (*p)--; /* Prev char is upr */ + break; + case 0xc6: /* Latin ext */ + switch (*p) { + case 0x83: + case 0x85: + case 0x88: + case 0x8c: + case 0x92: + case 0x99: + case 0xa1: + case 0xa3: + case 0xa5: + case 0xa8: + case 0xad: + case 0xb0: + case 0xb4: + case 0xb6: + case 0xb9: + case 0xbd: + (*p)--; /* Prev char is upr */ + break; + case 0x80: + *pExtChar = 0xc9; + (*p) = 0x83; + break; + case 0x95: + *pExtChar = 0xc7; + (*p) = 0xb6; + break; + case 0x9a: + *pExtChar = 0xc8; + (*p) = 0xbd; + break; + case 0x9e: + *pExtChar = 0xc8; + (*p) = 0xa0; + break; + case 0xbf: + *pExtChar = 0xc7; + (*p) = 0xb7; + break; + default: + break; + } + break; + case 0xc7: /* Latin ext */ + if (*p == 0x85) + (*p)--; /* Prev char is upr */ + else if (*p == 0x86) + (*p) = 0x84; + else if (*p == 0x88) + (*p)--; /* Prev char is upr */ + else if (*p == 0x89) + (*p) = 0x87; + else if (*p == 0x8b) + (*p)--; /* Prev char is upr */ + else if (*p == 0x8c) + (*p) = 0x8a; + else if ((*p >= 0x8d) + && (*p <= 0x9c) + && (!(*p % 2))) /* Even */ + (*p)--; /* Prev char is upr */ + else if ((*p >= 0x9e) + && (*p <= 0xaf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + else if (*p == 0xb2) + (*p)--; /* Prev char is upr */ + else if (*p == 0xb3) + (*p) = 0xb1; + else if (*p == 0xb5) + (*p)--; /* Prev char is upr */ + else if ((*p >= 0xb9) + && (*p <= 0xbf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0xc8: /* Latin ext */ + if ((*p >= 0x80) + && (*p <= 0x9f) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + else if ((*p >= 0xa2) + && (*p <= 0xb3) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + else if (*p == 0xbc) + (*p)--; /* Prev char is upr */ + /* 0xbf Three byte capital 0xe2 0xb1 0xbe */ + break; + case 0xc9: /* Latin ext */ + switch (*p) { + case 0x80: /* Three byte capital 0xe2 0xb1 0xbf */ + case 0x90: /* Three byte capital 0xe2 0xb1 0xaf */ + case 0x91: /* Three byte capital 0xe2 0xb1 0xad */ + case 0x92: /* Three byte capital 0xe2 0xb1 0xb0 */ + case 0x9c: /* Three byte capital 0xea 0x9e 0xab */ + case 0xa1: /* Three byte capital 0xea 0x9e 0xac */ + case 0xa5: /* Three byte capital 0xea 0x9e 0x8d */ + case 0xa6: /* Three byte capital 0xea 0x9e 0xaa */ + case 0xab: /* Three byte capital 0xe2 0xb1 0xa2 */ + case 0xac: /* Three byte capital 0xea 0x9e 0xad */ + case 0xb1: /* Three byte capital 0xe2 0xb1 0xae */ + case 0xbd: /* Three byte capital 0xe2 0xb1 0xa4 */ + break; + case 0x82: + (*p)--; /* Prev char is upr */ + break; + case 0x93: + *pExtChar = 0xc6; + (*p) = 0x81; + break; + case 0x94: + *pExtChar = 0xc6; + (*p) = 0x86; + break; + case 0x96: + *pExtChar = 0xc6; + (*p) = 0x89; + break; + case 0x97: + *pExtChar = 0xc6; + (*p) = 0x8a; + break; + case 0x98: + *pExtChar = 0xc6; + (*p) = 0x8e; + break; + case 0x99: + *pExtChar = 0xc6; + (*p) = 0x8f; + break; + case 0x9b: + *pExtChar = 0xc6; + (*p) = 0x90; + break; + case 0xa0: + *pExtChar = 0xc6; + (*p) = 0x93; + break; + case 0xa3: + *pExtChar = 0xc6; + (*p) = 0x94; + break; + case 0xa8: + *pExtChar = 0xc6; + (*p) = 0x97; + break; + case 0xa9: + *pExtChar = 0xc6; + (*p) = 0x96; + break; + case 0xaf: + *pExtChar = 0xc6; + (*p) = 0x9c; + break; + case 0xb2: + *pExtChar = 0xc6; + (*p) = 0x9d; + break; + case 0xb5: + *pExtChar = 0xc6; + (*p) = 0x9f; + break; + default: + if ((*p >= 0x87) + && (*p <= 0x8f) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + } + break; + + case 0xca: /* Latin ext */ + switch (*p) { + case 0x82: /* Three byte capital 0xea 0x9f 0x85 */ + case 0x87: /* Three byte capital 0xea 0x9e 0xb1 */ + case 0x9d: /* Three byte capital 0xea 0x9e 0xb2 */ + case 0x9e: /* Three byte capital 0xea 0x9e 0xb0 */ + break; + case 0x83: + *pExtChar = 0xc6; + (*p) = 0xa9; + break; + case 0x88: + *pExtChar = 0xc6; + (*p) = 0xae; + break; + case 0x89: + *pExtChar = 0xc9; + (*p) = 0x84; + break; + case 0x8a: + *pExtChar = 0xc6; + (*p) = 0xb1; + break; + case 0x8b: + *pExtChar = 0xc6; + (*p) = 0xb2; + break; + case 0x8c: + *pExtChar = 0xc9; + (*p) = 0x85; + break; + case 0x92: + *pExtChar = 0xc6; + (*p) = 0xb7; + break; + default: + break; + } + break; + case 0xcd: /* Greek & Coptic */ + switch (*p) { + case 0xb1: + case 0xb3: + case 0xb7: + (*p)--; /* Prev char is upr */ + break; + case 0xbb: + *pExtChar = 0xcf; + (*p) = 0xbd; + break; + case 0xbc: + *pExtChar = 0xcf; + (*p) = 0xbe; + break; + case 0xbd: + *pExtChar = 0xcf; + (*p) = 0xbf; + break; + default: + break; + } + break; + case 0xce: /* Greek & Coptic */ + if (*p == 0xac) + (*p) = 0x86; + else if (*p == 0xad) + (*p) = 0x88; + else if (*p == 0xae) + (*p) = 0x89; + else if (*p == 0xaf) + (*p) = 0x8a; + else if ((*p >= 0xb1) + && (*p <= 0xbf)) + (*p) -= 0x20; /* US ASCII shift */ + break; + case 0xcf: /* Greek & Coptic */ + if (*p == 0x82) { + *pExtChar = 0xce; + (*p) = 0xa3; + } + else if ((*p >= 0x80) + && (*p <= 0x8b)) { + *pExtChar = 0xce; + (*p) += 0x20; + } + else if (*p == 0x8c) { + *pExtChar = 0xce; + (*p) = 0x8c; + } + else if (*p == 0x8d) { + *pExtChar = 0xce; + (*p) = 0x8e; + } + else if (*p == 0x8e) { + *pExtChar = 0xce; + (*p) = 0x8f; + } + else if (*p == 0x91) + (*p) = 0xb4; + else if (*p == 0x97) + (*p) = 0x8f; + else if ((*p >= 0x98) + && (*p <= 0xaf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + else if (*p == 0xb2) + (*p) = 0xb9; + else if (*p == 0xb3) { + *pExtChar = 0xcd; + (*p) = 0xbf; + } + else if (*p == 0xb8) + (*p)--; /* Prev char is upr */ + else if (*p == 0xbb) + (*p)--; /* Prev char is upr */ + break; + case 0xd0: /* Cyrillic */ + if ((*p >= 0xb0) + && (*p <= 0xbf)) + (*p) -= 0x20; /* US ASCII shift */ + break; + case 0xd1: /* Cyrillic supplement */ + if ((*p >= 0x80) + && (*p <= 0x8f)) { + *pExtChar = 0xd0; + (*p) += 0x20; + } + else if ((*p >= 0x90) + && (*p <= 0x9f)) { + *pExtChar = 0xd0; + (*p) -= 0x10; + } + else if ((*p >= 0xa0) + && (*p <= 0xbf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0xd2: /* Cyrillic supplement */ + if (*p == 0x81) + (*p)--; /* Prev char is upr */ + else if ((*p >= 0x8a) + && (*p <= 0xbf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0xd3: /* Cyrillic supplement */ + if ((*p >= 0x81) + && (*p <= 0x8e) + && (!(*p % 2))) /* Even */ + (*p)--; /* Prev char is upr */ + else if (*p == 0x8f) + (*p) = 0x80; + else if ((*p >= 0x90) + && (*p <= 0xbf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0xd4: /* Cyrillic supplement & Armenian */ + if ((*p >= 0x80) + && (*p <= 0xaf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0xd5: /* Armenian */ + if ((*p >= 0xa1) + && (*p <= 0xaf)) { + *pExtChar = 0xd4; + (*p) += 0x10; + } + else if ((*p >= 0xb0) + && (*p <= 0xbf)) { + (*p) -= 0x30; + } + break; + case 0xd6: /* Armenian */ + if ((*p >= 0x80) + && (*p <= 0x86)) { + *pExtChar = 0xd5; + (*p) += 0x10; + } + break; + case 0xe1: /* Three byte code */ + pExtChar = p; + p++; + switch (*pExtChar) { + case 0x82: /* Georgian Asomtavruli */ + if ((*p >= 0xa0) + && (*p <= 0xbf)) { + *pExtChar = 0xb2; + (*p) -= 0x10; + } + break; + case 0x83: /* Georgian */ + /* Georgian Asomtavruli */ + if (((*p >= 0x80) + && (*p <= 0x85)) + || (*p == 0x87) + || (*p == 0x8d)) { + *pExtChar = 0xb2; + (*p) += 0x30; + } + /* Georgian mkhedruli */ + else if (((*p >= 0x90) + && (*p <= 0xba)) + || (*p == 0xbd) + || (*p == 0xbe) + || (*p == 0xbf)) { + *pExtChar = 0xb2; + } + break; + case 0x8f: /* Cherokee */ + if ((*p >= 0xb8) + && (*p <= 0xbd)) { + (*p) -= 0x08; + } + break; + case 0xb5: /* Latin ext */ + if (*p == 0xb9) { + *(p - 2) = 0xea; + *(p - 1) = 0x9d; + (*p) = 0xbd; + } + else if (*p == 0xbd) { + *(p - 2) = 0xe2; + *(p - 1) = 0xb1; + (*p) = 0xa3; + } + break; + case 0xb6: /* Latin ext */ + if (*p == 0x8e) { + *(p - 2) = 0xea; + *(p - 1) = 0x9f; + (*p) = 0x86; + } + break; + case 0xb8: /* Latin ext */ + if ((*p >= 0x80) + && (*p <= 0xbf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0xb9: /* Latin ext */ + if ((*p >= 0x80) + && (*p <= 0xbf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0xba: /* Latin ext */ + if ((*p >= 0x80) + && (*p <= 0x95) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + else if ((*p >= 0xa0) + && (*p <= 0xbf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0xbb: /* Latin ext */ + if ((*p >= 0x80) + && (*p <= 0xbf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0xbc: /* Greek ext */ + if ((*p >= 0x80) + && (*p <= 0x87)) + (*p) += 0x08; + else if ((*p >= 0x90) + && (*p <= 0x95)) + (*p) += 0x08; + else if ((*p >= 0xa0) + && (*p <= 0xa7)) + (*p) += 0x08; + else if ((*p >= 0xb0) + && (*p <= 0xb7)) + (*p) += 0x08; + break; + case 0xbd: /* Greek ext */ + if ((*p >= 0x80) + && (*p <= 0x85)) + (*p) += 0x08; + else if ((*p == 0x91) + || (*p == 0x93) + || (*p == 0x95) + || (*p == 0x97)) + (*p) += 0x08; + else if ((*p >= 0xa0) + && (*p <= 0xa7)) + (*p) += 0x08; + else if ((*p >= 0xb0) + && (*p <= 0xb1)) { + *(p - 1) = 0xbe; + (*p) += 0x0a; + } + else if ((*p >= 0xb2) + && (*p <= 0xb5)) { + *(p - 1) = 0xbf; + (*p) -= 0x2a; + } + else if ((*p >= 0xb6) + && (*p <= 0xb7)) { + *(p - 1) = 0xbf; + (*p) -= 0x1c; + } + else if ((*p >= 0xb8) + && (*p <= 0xb9)) { + *(p - 1) = 0xbf; + } + else if ((*p >= 0xba) + && (*p <= 0xbb)) { + *(p - 1) = 0xbf; + (*p) -= 0x10; + } + else if ((*p >= 0xbc) + && (*p <= 0xbd)) { + *(p - 1) = 0xbf; + (*p) -= 0x02; + } + break; + case 0xbe: /* Greek ext */ + if ((*p >= 0x80) + && (*p <= 0x87)) + (*p) += 0x08; + else if ((*p >= 0x90) + && (*p <= 0x97)) + (*p) += 0x08; + else if ((*p >= 0xa0) + && (*p <= 0xa7)) + (*p) += 0x08; + else if ((*p >= 0xb0) + && (*p <= 0xb1)) + (*p) += 0x08; + else if (*p == 0xb3) + (*p) += 0x09; + break; + case 0xbf: /* Greek ext */ + if (*p == 0x83) + (*p) += 0x09; + else if ((*p >= 0x90) + && (*p <= 0x91)) + *p += 0x08; + else if ((*p >= 0xa0) + && (*p <= 0xa1)) + (*p) += 0x08; + else if (*p == 0xa5) + (*p) += 0x07; + else if (*p == 0xb3) + (*p) += 0x09; + break; + default: + break; + } + break; + case 0xe2: /* Three byte code */ + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xb0: /* Glagolitic */ + if ((*p >= 0xb0) + && (*p <= 0xbf)) { + (*p) -= 0x30; + } + break; + case 0xb1: /* Glagolitic */ + if ((*p >= 0x80) + && (*p <= 0x9e)) { + *pExtChar = 0xb0; + (*p) += 0x10; + } + else { /* Latin ext */ + switch (*p) { + case 0xa1: + case 0xa8: + case 0xaa: + case 0xac: + case 0xb3: + case 0xb6: + (*p)--; /* Prev char is upr */ + break; + case 0xa5: /* Two byte capital 0xc8 0xba */ + case 0xa6: /* Two byte capital 0xc8 0xbe */ + break; + default: + break; + } + } + break; + case 0xb2: /* Coptic */ + if ((*p >= 0x80) + && (*p <= 0xbf) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0xb3: /* Coptic */ + if (((*p >= 0x80) + && (*p <= 0xa3) + && (*p % 2)) /* Odd */ + || (*p == 0xac) + || (*p == 0xae) + || (*p == 0xb3)) + (*p)--; /* Prev char is upr */ + break; + case 0xb4: /* Georgian */ + if (((*p >= 0x80) + && (*p <= 0xa5)) + || (*p == 0xa7) + || (*p == 0xad)) { + *(p - 2) = 0xe1; + *(p - 1) = 0xb2; + *(p) += 0x10; + } + break; + default: + break; + } + break; + case 0xea: /* Three byte code */ + pExtChar = p; + p++; + switch (*pExtChar) { + case 0x99: /* Cyrillic */ + if ((*p >= 0x80) + && (*p <= 0xad) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0x9a: /* Cyrillic */ + if ((*p >= 0x80) + && (*p <= 0x9b) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0x9c: /* Latin ext */ + if ((((*p >= 0xa2) + && (*p <= 0xaf)) + || ((*p >= 0xb2) + && (*p <= 0xbf))) + && (*p % 2)) /* Odd */ + (*p)--; /* Prev char is upr */ + break; + case 0x9d: /* Latin ext */ + if (((*p >= 0x80) + && (*p <= 0xaf) + && (*p % 2)) /* Odd */ + || (*p == 0xba) + || (*p == 0xbc) + || (*p == 0xbf)) + (*p)--; /* Prev char is upr */ + break; + case 0x9e: /* Latin ext */ + if (((((*p >= 0x80) + && (*p <= 0x87)) + || ((*p >= 0x96) + && (*p <= 0xa9)) + || ((*p >= 0xb4) + && (*p <= 0xbf))) + && (*p % 2)) /* Odd */ + || (*p == 0x8c) + || (*p == 0x91) + || (*p == 0x93)) + (*p)--; /* Prev char is upr */ + else if (*p == 0x94) { + *(p - 2) = 0xea; + *(p - 1) = 0x9f; + *(p) = 0x84; + } + break; + case 0x9f: /* Latin ext */ + if ((*p == 0x83) + || (*p == 0x88) + || (*p == 0x8a) + || (*p == 0xb6)) + (*p)--; /* Prev char is upr */ + break; + case 0xad: + /* Latin ext */ + if (*p == 0x93) { + *pExtChar = 0x9e; + (*p) = 0xb3; + } + /* Cherokee */ + else if ((*p >= 0xb0) + && (*p <= 0xbf)) { + *(p - 2) = 0xe1; + *pExtChar = 0x8e; + (*p) -= 0x10; + } + break; + case 0xae: /* Cherokee */ + if ((*p >= 0x80) + && (*p <= 0x8f)) { + *(p - 2) = 0xe1; + *pExtChar = 0x8e; + (*p) += 0x30; + } + else if ((*p >= 0x90) + && (*p <= 0xbf)) { + *(p - 2) = 0xe1; + *pExtChar = 0x8f; + (*p) -= 0x10; + } + break; + default: + break; + } + break; + case 0xef: /* Three byte code */ + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xbd: /* Latin fullwidth */ + if ((*p >= 0x81) + && (*p <= 0x9a)) { + *pExtChar = 0xbc; + (*p) += 0x20; + } + break; + default: + break; + } + break; + case 0xf0: /* Four byte code */ + pExtChar = p; + p++; + switch (*pExtChar) { + case 0x90: + pExtChar = p; + p++; + switch (*pExtChar) { + case 0x90: /* Deseret */ + if ((*p >= 0xa8) + && (*p <= 0xbf)) { + (*p) -= 0x28; + } + break; + case 0x91: /* Deseret */ + if ((*p >= 0x80) + && (*p <= 0x8f)) { + *pExtChar = 0x90; + (*p) += 0x18; + } + break; + case 0x93: /* Osage */ + if ((*p >= 0x98) + && (*p <= 0xa7)) { + *pExtChar = 0x92; + (*p) += 0x18; + } + else if ((*p >= 0xa8) + && (*p <= 0xbb)) + (*p) -= 0x28; + break; + case 0xb3: /* Old hungarian */ + if ((*p >= 0x80) + && (*p <= 0xb2)) + *pExtChar = 0xb2; + break; + default: + break; + } + break; + case 0x91: + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xa3: /* Warang citi */ + if ((*p >= 0x80) + && (*p <= 0x9f)) { + *pExtChar = 0xa2; + (*p) += 0x20; + } + break; + default: + break; + } + break; + case 0x96: + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xb9: /* Medefaidrin */ + if ((*p >= 0xa0) + && (*p <= 0xbf)) + (*p) -= 0x20; + break; + default: + break; + } + break; + case 0x9E: + pExtChar = p; + p++; + switch (*pExtChar) { + case 0xA4: /* Adlam */ + if ((*p >= 0xa2) + && (*p <= 0xbf)) + (*p) -= 0x22; + break; + case 0xA5: /* Adlam */ + if ((*p >= 0x80) + && (*p <= 0x83)) { + *(pExtChar) = 0xa4; + (*p) += 0x1e; + } + break; + default: + break; + } + break; + } + break; + default: + break; + } + pExtChar = 0; + } + p++; + } + } + return _pString; +} diff --git a/src/common/utf8util.h b/src/common/utf8util.h new file mode 100644 index 0000000..2d3cd8c --- /dev/null +++ b/src/common/utf8util.h @@ -0,0 +1,17 @@ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//https://stackoverflow.com/questions/36897781/how-to-uppercase-lowercase-utf-8-characters-in-c + +char* StrToUprExt(char* pString); +char* StrToLwrExt(char* pString); +int StrnCiCmp(const char* s1, const char* s2, size_t ztCount); +int StrCiCmp(const char* s1, const char* s2); +char* StrCiStr(const char* s1, const char* s2); + +#ifdef __cplusplus +} +#endif diff --git a/src/configs/plug/ProcBel.lng b/src/configs/plug/ProcBel.lng new file mode 100644 index 0000000..f1b7daf --- /dev/null +++ b/src/configs/plug/ProcBel.lng @@ -0,0 +1,26 @@ +.Language=Belarusian,Belarusian (Беларуская) + +"" +"" +"Спісак працессаў" +"Спісак працессаў" + +"Спісак працессаў: " +"process" + +"Працягнуць" +"Адмяніць" + +"Канфігурацыя дадатка process " +"Дадаць да меню &дыскаў" +"Дадаць да меню дада&ткаў" +"Дазволіць &лагіраванне:" + +"Налады плагіна process" +"&Захаваць налады плагіна process" + +"Спісак працессаў: " + +"Прэфікс:" + +"CPU" \ No newline at end of file diff --git a/src/configs/plug/ProcEng.hlf b/src/configs/plug/ProcEng.hlf new file mode 100644 index 0000000..603323f --- /dev/null +++ b/src/configs/plug/ProcEng.hlf @@ -0,0 +1,31 @@ +.Language=English,English +.PluginContents=Panel for configuring network interfaces and routes + +@Contents +$ #Panel Processes list# + + ~Panel Processes list~@ProcessesPanel@ + ~Configuration~@Config@ + +@ProcessesPanel +$^#Panel Processes list:# + The panel allows: + + - view information, edit (#F4#) processes information + +@Config +$^#Panel Processes: Configuration# + In this dialog, you can change the following options: + + #Add to disc menu# + Allows adding "Processes plugin" to the disk menu. + + #Add to plugins menu# + Allows adding "Processes plugin" items to the plug-in menu. + + #Display logs# + Allows, prohibits the output of logs to a file (set file path). + + #Save configuration to file# + Saves the configuration to a file ($HOME/.config/far2l/plugins/processes/config.ini), additionally allows you to manually fine-tune the columns (width, display names, etc.). + diff --git a/src/configs/plug/ProcEng.lng b/src/configs/plug/ProcEng.lng new file mode 100644 index 0000000..30bfe93 --- /dev/null +++ b/src/configs/plug/ProcEng.lng @@ -0,0 +1,26 @@ +.Language=English,English + +"" +"" +"Process list" +"Process list" + +"Process list: " +"process" + +"Ok" +"Cancel" + +"Process plugin configuration " +"Add to &Disks menu" +"Add to &Plugins menu" +"Enable &log:" + +"Process plugin settings" +"&Save Process plugin settings" + +"Process list: " + +"Prefix:" + +"CPU" \ No newline at end of file diff --git a/src/configs/plug/ProcRus.hlf b/src/configs/plug/ProcRus.hlf new file mode 100644 index 0000000..e445f85 --- /dev/null +++ b/src/configs/plug/ProcRus.hlf @@ -0,0 +1,31 @@ +.Language=Russian,Russian (Русский) +.PluginContents=Панель SQL + +@Contents +$ #Панель SQL + + ~Панель Processes~@ProcessesPanel@ + ~Конфигурация~@Config@ + +@ProcessesPanel +$^#Панель Processes + Панель позволяет: + + - просматривать (#F3#) и редактировать (#F4#) информацию о процессах + +@Config +$^#Панель SQL: Конфигурация# + В этом диалоге вы можете изменить следующие параметры: + + #Добавить в меню дисков# + Разрешает добавление в меню дисков пункта "Process list". + + #Добавить в меню плагинов# + Разрешает добавление в меню внешних модулей пункта "Process list". + + #Выводить логи# + Разрешает, запрещает вывод логов в файл (задается). + + #Сохранить конфигурацию в файл# + Сохраняет конфигурацию в файл ($HOME/.config/far2l/plugins/processes/config.ini), дополнительно позволяет вручную более тонко настроить столбцы (ширину, выводить ли вообще, имена). + diff --git a/src/configs/plug/ProcRus.lng b/src/configs/plug/ProcRus.lng new file mode 100644 index 0000000..0ef9ceb --- /dev/null +++ b/src/configs/plug/ProcRus.lng @@ -0,0 +1,26 @@ +.Language=Russian,Russian (Русский) + +"" +"" +"Список процессов" +"Список процессов" + +"Список процессов: " +"process" + +"Продолжить" +"Отменить" + +"Конфигурация плагина process " +"Добавить к меню &дисков" +"Добавить к меню &плагинов" +"Разрешить &логирование:" + +"Настройки плагина process" +"&Сохранить настройки плагина process" + +"Список процессов: " + +"Префикс:" + +"CPU" \ No newline at end of file diff --git a/src/farapi.cpp b/src/farapi.cpp new file mode 100644 index 0000000..95c12d4 --- /dev/null +++ b/src/farapi.cpp @@ -0,0 +1,148 @@ +#include "farapi.h" +#include "plugin.h" +#include +#include +#include +#include + +extern const char * LOG_FILE; +#define LOG_SOURCE_FILE "farapi.cpp" + +FarApi::FarApi(struct PluginStartupInfo & _psi, struct FarStandardFunctions & _FSF): + psi(_psi), + FSF(_FSF) +{ + LOG_INFO("\n"); +} + +FarApi::FarApi(): + psi(Plugin::psi), + FSF(Plugin::FSF) +{ + LOG_INFO("\n"); +} + + +FarApi::~FarApi() +{ + LOG_INFO("\n"); +} + +void FarApi::GetPanelInfo(PanelInfo & pi) const +{ + psi.Control(PANEL_ACTIVE, FCTL_GETPANELINFO, 0, (LONG_PTR)&pi); +} + + +PluginPanelItem * FarApi::GetPanelItem(intptr_t itemNum) const +{ + auto size = psi.Control(PANEL_ACTIVE, FCTL_GETPANELITEM, itemNum, 0); + PluginPanelItem * ppi = (PluginPanelItem *)malloc(size); + if( ppi != 0 ) + psi.Control(PANEL_ACTIVE, FCTL_GETPANELITEM, itemNum, (LONG_PTR)ppi); + return ppi; +} + +PluginPanelItem * FarApi::GetCurrentPanelItem(PanelInfo * piret) const +{ + struct PanelInfo pi = {0}; + psi.Control(PANEL_ACTIVE, FCTL_GETPANELINFO, 0, (LONG_PTR)&pi); + if( piret ) + *piret = pi; + return GetPanelItem(pi.CurrentItem); +} + +PluginPanelItem * FarApi::GetSelectedPanelItem(intptr_t selectedItemNum) const +{ + auto size = psi.Control(PANEL_ACTIVE, FCTL_GETSELECTEDPANELITEM, selectedItemNum, 0); + PluginPanelItem * ppi = (PluginPanelItem *)malloc(size); + if( ppi != 0 ) + psi.Control(PANEL_ACTIVE, FCTL_GETSELECTEDPANELITEM, selectedItemNum, (LONG_PTR)ppi); + return ppi; +} + +void FarApi::FreePanelItem(PluginPanelItem * ppi) const +{ + free((void *)ppi); +} + +const wchar_t * FarApi::GetMsg(int msgId) const +{ + assert( psi.GetMsg != 0 ); + return psi.GetMsg(Plugin::psi.ModuleNumber, msgId); +} + +int FarApi::Select(HANDLE hDlg, const wchar_t ** elements, int count, uint32_t setIndex) const +{ + int index = 0; + auto menuElements = std::make_unique(count); + memset(menuElements.get(), 0, sizeof(FarMenuItem)*count); + do { + menuElements[index].Text = elements[index]; + } while( ++index < count ); + + menuElements[0].Selected = 1; + + index = psi.Menu(Plugin::psi.ModuleNumber, -1, -1, 0, FMENU_WRAPMODE|FMENU_AUTOHIGHLIGHT, \ + L"Select:", 0, L"", nullptr, nullptr, menuElements.get(), count); + if( index >= 0 && index < count ) + psi.SendDlgMessage(hDlg, DM_SETTEXTPTR, setIndex, (LONG_PTR)menuElements[index].Text); + return index; +} + +int FarApi::SelectNum(HANDLE hDlg, const wchar_t ** elements, int count, const wchar_t * subTitle, uint32_t setIndex) const +{ + auto index = Select(hDlg, elements, count, setIndex); + if( index == (count-1) ) { + static wchar_t num[sizeof("4294967296")] = {0}; + psi.InputBox(L"Enter number:", subTitle, 0, 0, num, ARRAYSIZE(num), 0, FIB_NOUSELASTHISTORY); + psi.SendDlgMessage(hDlg, DM_SETTEXTPTR, setIndex, (LONG_PTR)num); + psi.SendDlgMessage(hDlg, DM_REDRAW, 0, 0); + } + return index; +} + +std::wstring FarApi::towstr(const char * name) const +{ + std::string _s(name); + return std::wstring(_s.begin(), _s.end()); +} + +std::string FarApi::tostr(const wchar_t * name) const +{ + std::wstring _s(name); + return std::string(_s.begin(), _s.end()); +} + +const wchar_t * FarApi::DublicateCountString(int64_t value) const +{ + wchar_t max64[sizeof("18446744073709551615")] = {0}; + +#if INTPTR_MAX == INT32_MAX + if( FSF.snprintf(max64, ARRAYSIZE(max64), L"%lld", value) > 0 ) +#elif INTPTR_MAX == INT64_MAX + if( FSF.snprintf(max64, ARRAYSIZE(max64), L"%ld", value) > 0 ) +#else + #error "Environment not 32 or 64-bit." +#endif + return wcsdup(max64); + + return wcsdup(L""); +} + +const wchar_t * FarApi::DublicateFileSizeString(uint64_t value) const +{ + if( value > 100 * 1024 ) { + std::wstring _tmp = FileSizeString(value); + return wcsdup(_tmp.c_str()); + } + return DublicateCountString((int64_t)value); +} + +const wchar_t * FarApi::DublicateFloatPercentString(float value) const +{ + wchar_t max64[sizeof("186744073709551615.18%")] = {0}; + if( FSF.snprintf(max64, ARRAYSIZE(max64), L"%.02f%%", value) > 0 ) + return wcsdup(max64); + return wcsdup(L""); +} \ No newline at end of file diff --git a/src/farapi.h b/src/farapi.h new file mode 100644 index 0000000..6c336ed --- /dev/null +++ b/src/farapi.h @@ -0,0 +1,34 @@ +#ifndef __FARAPI_H__ +#define __FARAPI_H__ + +#include +#include + +class FarApi { +private: + struct PluginStartupInfo & psi; + struct FarStandardFunctions & FSF; +public: + // towstr can use only for ASCII symbols + std::wstring towstr(const char * name) const; + std::string tostr(const wchar_t * name) const; + + const wchar_t * DublicateFloatPercentString(float value) const; + const wchar_t * DublicateCountString(int64_t value) const; + const wchar_t * DublicateFileSizeString(uint64_t value) const; + + void GetPanelInfo(PanelInfo & pi) const; + PluginPanelItem * GetPanelItem(intptr_t itemNum) const; + void FreePanelItem(PluginPanelItem * ppi) const; + PluginPanelItem * GetCurrentPanelItem(PanelInfo * piret = nullptr) const; + PluginPanelItem * GetSelectedPanelItem(intptr_t selectedItemNum) const; + const wchar_t * GetMsg(int msgId) const; + int Select(HANDLE hDlg, const wchar_t ** elements, int count, uint32_t setIndex) const; + int SelectNum(HANDLE hDlg, const wchar_t ** elements, int count, const wchar_t * subTitle, uint32_t setIndex) const; + + FarApi(struct PluginStartupInfo & psi, struct FarStandardFunctions & FSF); + FarApi(); + virtual ~FarApi(); +}; + +#endif /* __FARAPI_H__ */ diff --git a/src/farconnect.cpp b/src/farconnect.cpp new file mode 100644 index 0000000..28d9af8 --- /dev/null +++ b/src/farconnect.cpp @@ -0,0 +1,189 @@ +#include "procplugin.h" + +#include +#include +#include + +extern const char * LOG_FILE; +#define LOG_SOURCE_FILE "farconnect.cpp" + +// plugin +static class ProcPlugin * gPlugin = 0; + +// export for processes +int RootExec(const char * cmd) +{ + assert( gPlugin != 0 ); + if( !gPlugin ) + return -1; + std::string _acmd(cmd); + std::wstring _cmd(_acmd.begin(), _acmd.end()); + int res = gPlugin->FSF.Execute(_cmd.c_str(), EF_SUDO); + LOG_INFO("exec \"%s\" return %d\n", cmd, res); + return res; +} + +int Exec(const char * cmd) +{ + assert( gPlugin != 0 ); + if( !gPlugin ) + return -1; + std::string _acmd(cmd); + std::wstring _cmd(_acmd.begin(), _acmd.end()); + int res = gPlugin->FSF.Execute(_cmd.c_str(), 0); + LOG_INFO("exec \"%s\" return %d\n", cmd, res); + return res; +} + +SHAREDSYMBOL int WINAPI _export ConfigureW(int itemNumber) +{ + LOG_INFO("\n"); + assert( gPlugin != 0 ); + return gPlugin->Configure(itemNumber); +} + +SHAREDSYMBOL int WINAPI _export ProcessKeyW(HANDLE hPlugin,int key,unsigned int controlState) +{ + return gPlugin->ProcessKey(hPlugin, key, controlState); +} + +#include + +SHAREDSYMBOL int WINAPI _export ProcessEventW(HANDLE hPlugin,int event,void *param) +{ + switch(event) { + case FE_CHANGEVIEWMODE: + LOG_INFO(":FE_CHANGEVIEWMODE \"%S\"\n", (const wchar_t *)param); + //res = FALSE; + break; + case FE_REDRAW: + LOG_INFO(":FE_REDRAW %p\n", param); + //res = FALSE; // redraw + //res = TRUE; // no redraw + break; + case FE_IDLE: + { + // t = clock(); + //LOG_INFO(":FE_IDLE %p\n", param); + static clock_t t; + clock_t t1 = clock(); + LOG_INFO("FE_IDLE %p time %f\n", param, ((double)t1 - t) / CLOCKS_PER_SEC); + t = t1; + //res = FALSE; + } + break; + case FE_CLOSE: + LOG_INFO(":FE_CLOSE %p\n", param); + //res = FALSE; // close panel + // res = TRUE; // no close panel + break; + case FE_BREAK: + // Ctrl-Break is pressed + // Processing of this event is performed in separate thread, + // plugin must not use FAR service functions. +#if INTPTR_MAX == INT32_MAX + LOG_INFO(":FE_BREAK CTRL_BREAK_EVENT %llu\n", param); +#elif INTPTR_MAX == INT64_MAX + LOG_INFO(":FE_BREAK CTRL_BREAK_EVENT %lu\n", param); +#else + #error "Environment not 32 or 64-bit." +#endif + //res = FALSE; + break; + case FE_COMMAND: + LOG_INFO(":FE_COMMAND \"%S\"\n", (const wchar_t *)param); + //res = FALSE; // allow standard command execution + //res = TRUE; // TRUE if it is going to process the command internally. + break; + case FE_GOTFOCUS: + LOG_INFO(":FE_GOTFOCUS %p\n", param); + //res = FALSE; + break; + case FE_KILLFOCUS: + LOG_INFO(":FE_KILLFOCUS %p\n", param); + //res = FALSE; + break; + default: + LOG_INFO(":UNKNOWN %p\n", param); + break; + }; + return gPlugin->ProcessEvent(hPlugin, event, param); +} + +SHAREDSYMBOL void WINAPI _export FreeFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber) +{ + LOG_INFO("hPlugin %p pPanelItem %p ItemsNumber %u\n", hPlugin, PanelItem, ItemsNumber); + gPlugin->FreeFindData(hPlugin, PanelItem, ItemsNumber); + return; +} + +SHAREDSYMBOL int WINAPI _export GetFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,int OpMode) +{ + LOG_INFO("hPlugin %p OpMode %d *pPanelItem %p *pItemsNumber %u\n", hPlugin, OpMode, *pPanelItem, *pItemsNumber); + gPlugin->GetFindData(hPlugin, pPanelItem, pItemsNumber); + return TRUE; +} + +SHAREDSYMBOL void WINAPI _export GetOpenPluginInfoW(HANDLE hPlugin, struct OpenPluginInfo *info) +{ + LOG_INFO("hPlugin %p info %p\n", hPlugin, info); + gPlugin->GetOpenPluginInfo(hPlugin, info); +} + +SHAREDSYMBOL HANDLE WINAPI _export OpenPluginW(int openFrom, INT_PTR item) +{ + if( openFrom == OPEN_COMMANDLINE && item ) + LOG_INFO("openFrom=%u, item=%S\n", openFrom, reinterpret_cast(item)); + else + LOG_INFO("openFrom=%u, item=%u\n", openFrom, item); + return gPlugin->OpenPlugin(openFrom, item); +} + +SHAREDSYMBOL void WINAPI _export ClosePluginW(HANDLE hPlugin) +{ + LOG_INFO("hPlugin 0x%p\n", hPlugin); + gPlugin->ClosePlugin(hPlugin); +} + +SHAREDSYMBOL void WINAPI _export GetPluginInfoW(struct PluginInfo *info) +{ + LOG_INFO("(struct PluginInfo *info = %p)\n", info); + gPlugin->GetPluginInfo(info); +} + +SHAREDSYMBOL void WINAPI _export SetStartupInfoW(const struct PluginStartupInfo * info) +{ + assert( gPlugin == 0 ); + gPlugin = new ProcPlugin(info); +} + +SHAREDSYMBOL HANDLE WINAPI _export OpenFilePluginW(const wchar_t *name,const unsigned char *data,int dataSize,int opMode) +{ + LOG_INFO("OpenFilePluginW(Name=%S,*Data=%p,DataSize=%d,OpMode=%d)\n", name, data, dataSize, opMode); + return gPlugin->OpenFilePlugin(name, data, dataSize, opMode); +} + +SHAREDSYMBOL int WINAPI _export SetDirectoryW(HANDLE hPlugin, const wchar_t *dir, int opMode) +{ + LOG_INFO("SetDirectoryW(hPlugin=%p, Dir=%S, OpMode=%d)\n", hPlugin, dir, opMode); + return gPlugin->SetDirectory(hPlugin, dir, opMode); +} + +SHAREDSYMBOL int WINAPI _export DeleteFilesW(HANDLE hPlugin, struct PluginPanelItem *panelItem, int itemsNumber, int opMode) +{ + LOG_INFO("DeleteFilesW(hPlugin=%p, PanelItem=%p, ItemsNumber %d, OpMode=%d)\n", hPlugin, panelItem, itemsNumber, opMode); + return gPlugin->DeleteFiles(hPlugin, panelItem, itemsNumber, opMode); +} + +SHAREDSYMBOL int WINAPI _export GetMinFarVersionW() +{ +// LOG_INFO("return 0x%08X\n", FARMANAGERVERSION); + return FARMANAGERVERSION; +} + +SHAREDSYMBOL void WINAPI _export ExitFARW() +{ + LOG_INFO("\n"); + delete gPlugin; + gPlugin = 0; +} diff --git a/src/fardialog.cpp b/src/fardialog.cpp new file mode 100644 index 0000000..998013d --- /dev/null +++ b/src/fardialog.cpp @@ -0,0 +1,498 @@ +#include "fardialog.h" +#include "plugincfg.h" +#include "lng.h" +#include "plugin.h" + +#include +#include + +#include +#include +#include + +extern const char * LOG_FILE; +#define LOG_SOURCE_FILE "fardialog.cpp" + + +#if INTPTR_MAX == INT32_MAX +#define LLFMT L"%lld" +#elif INTPTR_MAX == INT64_MAX +#define LLFMT L"%ld" +#else + #error "Environment not 32 or 64-bit." +#endif + +void FarDlgConstructor::SetText(unsigned int itemNum, const wchar_t * str, bool dublicate) +{ + static const wchar_t * empty_string = L""; + if( free_items.find(itemNum) != free_items.end() ) { + free((void *)dlg[itemNum].PtrData); + free_items.erase(itemNum); + } + + if( str ) { + if( dublicate ) { + free_items.insert(itemNum); + dlg[itemNum].PtrData = wcsdup(str); + } else { + dlg[itemNum].PtrData = str; + } + } else + dlg[itemNum].PtrData = empty_string; + +} + +void FarDlgConstructor::SetCountText(unsigned int itemNum, int64_t value) +{ + wchar_t max64[sizeof("18446744073709551615")] = {0}; + if( Plugin::FSF.snprintf(max64, ARRAYSIZE(max64), LLFMT, value) > 0 ) + SetText(itemNum, max64, true); + return; +} + +void FarDlgConstructor::SetCountHex32Text(unsigned int itemNum, uint32_t value, bool prefix) +{ + wchar_t maxhex32[sizeof("0xFFFFFFFF")] = {0}; + if( Plugin::FSF.snprintf(maxhex32, ARRAYSIZE(maxhex32), prefix ? L"0x%08X":L"%08X", value) > 0 ) + SetText(itemNum, maxhex32, true); + return; +} + +void FarDlgConstructor::SetFileSizeText(unsigned int itemNum, uint64_t value) +{ + if( value > 100 * 1024 ) { + std::wstring _tmp = FileSizeString(value); + SetText(itemNum, _tmp.c_str(), true); + return; + } + return SetCountText(itemNum, (int64_t)value); +} + +void FarDlgConstructor::SetX(unsigned int itemNum, int x) +{ + dlg[itemNum].X1 = x; +} + +void FarDlgConstructor::SetSelected(unsigned int itemNum, bool selected) +{ + dlg[itemNum].Selected = selected; +} + +void FarDlgConstructor::SetFocus(unsigned int itemNum) +{ + dlg[itemNum].Focus = 1; +} + +void FarDlgConstructor::SetDefaultButton(unsigned int itemNum) +{ + dlg[itemNum].DefaultButton = 1; +} + +DWORD FarDlgConstructor::GetFlags(unsigned int itemNum) +{ + return dlg[itemNum].Flags; +} + +void FarDlgConstructor::SetFlags(unsigned int itemNum, DWORD flags) +{ + dlg[itemNum].Flags = flags; +} + +void FarDlgConstructor::OrFlags(unsigned int itemNum, DWORD flags) +{ + dlg[itemNum].Flags |= flags; +} + +void FarDlgConstructor::AndFlags(unsigned int itemNum, DWORD flags) +{ + dlg[itemNum].Flags &= flags; +} + +void FarDlgConstructor::HideItems(unsigned int itemFirst, unsigned int itemLast) +{ + assert( itemFirst <= itemLast ); + for( unsigned int i = itemFirst; i <= itemLast; i++ ) + dlg[i].Flags |= DIF_HIDDEN; +} + +void FarDlgConstructor::UnhideItems(unsigned int itemFirst, unsigned int itemLast) +{ + assert( itemFirst <= itemLast ); + for( unsigned int i = itemFirst; i <= itemLast; i++ ) + dlg[i].Flags &= ~DIF_HIDDEN; +} + +void FarDlgConstructor::SetMaxTextLen(unsigned int itemNum, size_t maxLen) +{ + dlg[itemNum].MaxLen = maxLen; +} + +// return last appended item index +unsigned int FarDlgConstructor::Append(const DlgConstructorItem * item) +{ + const wchar_t * empty_string = L""; + + if( item->type == DI_ENDDIALOG ) + return (dlg.size() - 1); + +/* +struct FarDialogItem +{ + int Type; + int X1,Y1,X2,Y2; + int Focus; + union + { + DWORD_PTR Reserved; + int Selected; + const wchar_t *History; + const wchar_t *Mask; + struct FarList *ListItems; + int ListPos; + CHAR_INFO *VBuf; + } +#ifdef _FAR_NO_NAMELESS_UNIONS + Param +#endif + ; + DWORD Flags; + int DefaultButton; + + const wchar_t *PtrData; + size_t MaxLen; // terminate 0 not included (if == 0 string size is unlimited) +}; +*/ + struct FarDialogItem fdi = { + item->type, + item->X1, + item->incY ? (++yEnd):yEnd, + item->X2, + yEnd, + 0, + {0}, + item->flags, + 0, + (item->data.ptrData && item->data.ptrData < (const wchar_t *)MMaxString) ? \ + (Plugin::psi.GetMsg(Plugin::psi.ModuleNumber, item->data.lngIdstring)):\ + (item->data.ptrData ? item->data.ptrData:empty_string), + 0}; + dlg.push_back(fdi); + + //LOG_INFO("itemNum: %u text: %S item.Type %d total: %d\n", dlg.size() - 1, fdi.PtrData ? fdi.PtrData:L"NONE", item->type, GetNumberOfItems()); + + dlg[0].Y2 = (yEnd + 1); + return (dlg.size() - 1); +} + +// return next appended item index +unsigned int FarDlgConstructor::AppendItems(const DlgConstructorItem * items) +{ + while( items->type != DI_ENDDIALOG ) { + Append(items); + items++; + } + return dlg.size(); +} + +// return index of first element in appended suffix +unsigned int FarDlgConstructor::AppendOkCancel(void) { + static const DlgConstructorItem suffix[] = { + // Type NewLine X1 X2 Flags PtrData + {DI_TEXT, true, 5, 0, DIF_BOXCOLOR|DIF_SEPARATOR, {0}}, + {DI_BUTTON, true, 0, 0, DIF_CENTERGROUP, {.lngIdstring = MOk}}, + {DI_BUTTON, false, 0, 0, DIF_CENTERGROUP, {.lngIdstring = MCancel}}, + {DI_ENDDIALOG, 0} + }; + unsigned int suffixOff = dlg.size(); + AppendItems(&suffix[0]); + return suffixOff; +} + +FarDlgConstructor::FarDlgConstructor(const DlgConstructorItem * items, int y) +{ + xStart = items->X1; + yStart = y; + xEnd = items->X2 + xStart + 1; + yEnd = y; + AppendItems(items); +} + +FarDlgConstructor::FarDlgConstructor(const wchar_t * title, int width, int x, int y) +{ + xStart = x; + yStart = y; + xEnd = width; + yEnd = y; + + DlgConstructorItem item = {DI_DOUBLEBOX, false, xStart, xEnd-(xStart+1), 0, {.ptrData = title}}; + Append(&item); +} + +FarDlgConstructor::~FarDlgConstructor() +{ + for( auto itemNum : free_items ) { + LOG_INFO("free: %d\n", itemNum); + free((void *)dlg[itemNum].PtrData); + } +} + +unsigned int FarDlgConstructor::GetNumberOfItems(void) +{ + return dlg.size(); +} + +FarDialogItem * FarDlgConstructor::GetDialogItem(unsigned int itemNum) +{ + if( dlg.size() <= itemNum ) + return nullptr; + return &dlg[itemNum]; +} + +const wchar_t * FarDlgConstructor::GetConstText(unsigned int itemNum) const +{ + return dlg[itemNum].PtrData; +} + +const wchar_t * FarDlgConstructor::GetHelpTopic(void) +{ + return helpTopic.c_str(); +} + +void FarDlgConstructor::SetHelpTopic(const wchar_t * help) +{ + helpTopic = help; +} + +FarDialog::FarDialog(FarDlgConstructor * data, FARWINDOWPROC dlgProc, LONG_PTR param): + fdc(data) +{ + FarDialogItem * item = fdc->GetDialogItem(0); + hDlg = Plugin::psi.DialogInit( + Plugin::psi.ModuleNumber, // INT_PTR PluginNumber + -1, // int X1, + -1, // int Y1, + fdc->xEnd, // int X2, + fdc->yEnd+fdc->yStart+2, // int Y2, + fdc->GetHelpTopic(), // const wchar_t *HelpTopic, + item, // struct FarDialogItem *Item, + fdc->GetNumberOfItems(), // unsigned int ItemsNumber, + 0, // DWORD Reserved, + 0, // DWORD Flags, + dlgProc, // FARWINDOWPROC DlgProc, + (LONG_PTR)param); // LONG_PTR Param + + if (hDlg == INVALID_HANDLE_VALUE) { + LOG_ERROR("DialogInit()\n"); + } + LOG_INFO("\n"); +} + +FarDialog::~FarDialog() +{ + LOG_INFO("\n"); + if( hDlg != INVALID_HANDLE_VALUE ) + Plugin::psi.DialogFree(hDlg); +} + +int FarDialog::Run(void) +{ + LOG_INFO("\n"); + return hDlg != INVALID_HANDLE_VALUE ? Plugin::psi.DialogRun(hDlg):-1; +} + + +ItemChange::ItemChange(unsigned int itemNum_, int type_): itemNum(itemNum_), type(type_) +{ + const wchar_t * const empty_string = L""; + oldVal.ptrData = nullptr; + ptrData = empty_string; + empty = true; + if( type == DI_BUTTON ) + newVal.ptrData = ptrData.c_str(); + else + newVal.ptrData = nullptr; +} + +ItemChange::ItemChange(ItemChange && old) +{ + itemNum = old.itemNum; + type = old.type; + empty = old.empty; + oldVal.ptrData = old.oldVal.ptrData; + ptrData = std::move(old.ptrData); + if( type == DI_BUTTON ) + newVal.ptrData = ptrData.c_str(); + else + newVal.ptrData = old.newVal.ptrData; +} + +bool FarDialog::CreateChangeList(std::vector & chlst) +{ + bool change = false; + unsigned int itemNum = 0; + for( auto & item : *fdc ) { + ItemChange ich(itemNum, item.Type); + //LOG_INFO("itemNum: %u text: %S item.Type %d total: %d\n", itemNum, item.PtrData ? item.PtrData:L"NONE", item.Type, fdc->GetNumberOfItems()); + switch(item.Type) { + case DI_BUTTON: + ich.oldVal.ptrData = item.PtrData; + ich.ptrData = GetText(itemNum); + ich.newVal.ptrData = ich.ptrData.c_str(); + ich.empty = ich.ptrData.empty(); + if( Plugin::FSF.LStricmp(ich.newVal.ptrData, ich.oldVal.ptrData) ) { + LOG_INFO("%u. DI_BUTTON: change from: %S to %S\n", itemNum, ich.oldVal.ptrData, ich.newVal.ptrData); + change = true; + chlst.push_back(std::move(ich)); + } + break; + case DI_CHECKBOX: + case DI_RADIOBUTTON: + ich.oldVal.Selected = item.Selected; + ich.newVal.Selected = GetCheck(itemNum); + if( ich.newVal.Selected != ich.oldVal.Selected ) { + change = true; + chlst.push_back(std::move(ich)); + } + break; + case DI_EDIT: + ich.oldVal.ptrData = item.PtrData; + ich.newVal.ptrData = GetConstText(itemNum); + ich.empty = (wcslen(ich.newVal.ptrData) == 0); + if( Plugin::FSF.LStricmp(ich.newVal.ptrData, ich.oldVal.ptrData) ) { + LOG_INFO("%u. DI_EDIT: change from: %S to %S\n", itemNum, ich.oldVal.ptrData, ich.newVal.ptrData); + change = true; + chlst.push_back(std::move(ich)); + } + break; + } + itemNum++; + } + return change; +} + +bool FarDialog::GetCheck(unsigned int itemNum) +{ + return bool(Plugin::psi.SendDlgMessage(hDlg, DM_GETCHECK, itemNum, 0)); +} + +std::wstring FarDialog::GetText(unsigned int itemNum) +{ + std::wstring text; + size_t len = Plugin::psi.SendDlgMessage(hDlg, DM_GETTEXTLENGTH, itemNum, 0); + if( len ) { + auto buf = std::make_unique(len+1); + Plugin::psi.SendDlgMessage(hDlg, DM_GETTEXTPTR, itemNum, (ULONG_PTR)buf.get()); + text = buf.get(); + } + return text; +} + +const wchar_t * FarDialog::GetConstText(unsigned int itemNum) +{ + return (const wchar_t *)Plugin::psi.SendDlgMessage(hDlg, DM_GETCONSTTEXTPTR, itemNum, 0); +} + +int32_t FarDialog::GetInt32(unsigned int itemNum) +{ + return Plugin::FSF.atoi(GetConstText(itemNum)); +} + +int64_t FarDialog::GetInt64(unsigned int itemNum) +{ + return Plugin::FSF.atoi64(GetConstText(itemNum)); +} + +int64_t FarDialog::GetInt64FromHex(unsigned int itemNum, bool prefix) +{ + unsigned long long ofs = 0; + Plugin::FSF.sscanf(GetConstText(itemNum), prefix ? L"0x%llx":L"%llx", &ofs); + return ofs; +} + +int32_t FarDialog::GetInt32FromHex(unsigned int itemNum, bool prefix) +{ + return (int32_t)GetInt64FromHex(itemNum, prefix); +} + +HANDLE FarDialog::GetDlg(void) +{ + return hDlg; +} + +void ChangeDialogItemsView(HANDLE hDlg, unsigned int itemFirst, unsigned int itemLast, bool hide, bool disable) +{ + assert( itemFirst <= itemLast ); + for(unsigned int i = itemFirst; i <= itemLast; i++ ) { + struct FarDialogItem *dlg = (FarDialogItem *)malloc(Plugin::psi.SendDlgMessage(hDlg,DM_GETDLGITEM,i,0)); + if( dlg ) { + Plugin::psi.SendDlgMessage(hDlg,DM_GETDLGITEM,i,(LONG_PTR)dlg); + if( disable ) + dlg->Flags |= DIF_DISABLE; + else + dlg->Flags &= ~DIF_DISABLE; + + if( hide ) + dlg->Flags |= DIF_HIDDEN; + else + dlg->Flags &= ~DIF_HIDDEN; + + Plugin::psi.SendDlgMessage(hDlg,DM_SETDLGITEM,i,(LONG_PTR)dlg); + free(dlg); + } + } + Plugin::psi.SendDlgMessage(hDlg, DM_REDRAW, 0, 0); +} + +void HideDialogItems(HANDLE hDlg, unsigned int itemFirst, unsigned int itemLast) +{ + ChangeDialogItemsView(hDlg, itemFirst, itemLast, true, false); +} + +void UnhideDialogItems(HANDLE hDlg, unsigned int itemFirst, unsigned int itemLast) +{ + ChangeDialogItemsView(hDlg, itemFirst, itemLast, false, false); +} + +void DisableDialogItems(HANDLE hDlg, unsigned int itemFirst, unsigned int itemLast) +{ + ChangeDialogItemsView(hDlg, itemFirst, itemLast, false, true); +} + +void EnableDialogItems(HANDLE hDlg, unsigned int itemFirst, unsigned int itemLast) +{ + ChangeDialogItemsView(hDlg, itemFirst, itemLast, false, false); +} + +uint64_t GetNumberItem(HANDLE hDlg, unsigned int itemNum) +{ + size_t len = Plugin::psi.SendDlgMessage(hDlg, DM_GETTEXTLENGTH, itemNum, 0); + if( len ) { + auto buf = std::make_unique(len+1); + Plugin::psi.SendDlgMessage(hDlg, DM_GETTEXTPTR, itemNum, (ULONG_PTR)buf.get()); + return Plugin::FSF.atoi64(buf.get()); + } + return 0; +} + +std::wstring GetText(HANDLE hDlg, unsigned int itemNum) +{ + std::wstring text; + size_t len = Plugin::psi.SendDlgMessage(hDlg, DM_GETTEXTLENGTH, itemNum, 0); + if( len ) { + auto buf = std::make_unique(len+1); + Plugin::psi.SendDlgMessage(hDlg, DM_GETTEXTPTR, itemNum, (ULONG_PTR)buf.get()); + text = buf.get(); + } + return text; +} + +bool ShowHideElements(HANDLE hDlg, uint32_t chk, uint32_t chkStore, uint32_t begin, uint32_t end) +{ + bool prev = bool(Plugin::psi.SendDlgMessage(hDlg, DM_GETCHECK, chkStore, 0)); + bool enabled = bool(Plugin::psi.SendDlgMessage(hDlg, DM_GETCHECK, chk, 0)); + if( prev != enabled ) { + Plugin::psi.SendDlgMessage(hDlg, DM_SETCHECK, chkStore, enabled); + ChangeDialogItemsView(hDlg, begin, end, false, !enabled); + } + return enabled; +} diff --git a/src/fardialog.h b/src/fardialog.h new file mode 100644 index 0000000..9ff0f93 --- /dev/null +++ b/src/fardialog.h @@ -0,0 +1,125 @@ +#ifndef __FARDIALOG_H__ +#define __FARDIALOG_H__ + +#include +#include +#include +#include + +typedef struct { + int type; + bool incY; + int X1,X2; + DWORD flags; + union { + const wchar_t * ptrData; + FarLangMsgID lngIdstring; + } data; +} DlgConstructorItem; + +struct ItemChange { + unsigned int itemNum; + int type; + union { + int Selected; + const wchar_t * ptrData; + } oldVal; + union { + int Selected; + const wchar_t * ptrData; + } newVal; + std::wstring ptrData; + bool empty; + explicit ItemChange(unsigned int itemNum, int type); + ItemChange(ItemChange && old); +}; + +enum { + WinSuffixSeparatorIndex, + WinSuffixOkIndex, + WinSuffixCancelIndex +}; + +#define DEFAUL_Y_START 1 +#define DEFAUL_X_START 3 + +#define DI_ENDDIALOG (DI_USERCONTROL+1) + +class FarDlgConstructor { + private: + std::vector dlg; + std::set free_items; + std::wstring helpTopic; + public: + int xStart, yStart, xEnd, yEnd; + + typedef std::vector::const_iterator const_iterator; + const_iterator begin() const { return dlg.begin(); }; + const_iterator end() const { return dlg.end(); }; + + unsigned int Append(const DlgConstructorItem * item); + unsigned int AppendItems(const DlgConstructorItem * items); + unsigned int AppendOkCancel(void); + + const wchar_t * GetHelpTopic(void); + void SetHelpTopic(const wchar_t * help); + unsigned int GetNumberOfItems(void); + FarDialogItem * GetDialogItem(unsigned int itemNum); + const wchar_t * GetConstText(unsigned int itemNum) const; + + void SetSelected(unsigned int itemNum, bool selected); + void SetFlags(unsigned int itemNum, DWORD flags); + void OrFlags(unsigned int itemNum, DWORD flags); + void AndFlags(unsigned int itemNum, DWORD flags); + + void HideItems(unsigned int itemFirst, unsigned int itemLast); + void UnhideItems(unsigned int itemFirst, unsigned int itemLast); + + DWORD GetFlags(unsigned int itemNum); + void SetFocus(unsigned int itemNum); + void SetDefaultButton(unsigned int itemNum); + void SetMaxTextLen(unsigned int itemNum, size_t maxLen); + void SetText(unsigned int itemNum, const wchar_t * text, bool dublicate=false); + void SetX(unsigned int itemNum, int x); + void SetCountText(unsigned int itemNum, int64_t value); + void SetCountHex32Text(unsigned int itemNum, uint32_t value, bool prefix = true); + void SetFileSizeText(unsigned int itemNum, uint64_t value); + + + FarDlgConstructor(const DlgConstructorItem * items, int yStart = DEFAUL_Y_START); + FarDlgConstructor(const wchar_t * title, + int width, // xEnd + int xStart = DEFAUL_X_START, + int yStart = DEFAUL_Y_START); + ~FarDlgConstructor(); +}; + +void ChangeDialogItemsView(HANDLE hDlg, unsigned int itemFirst, unsigned int itemLast, bool hide, bool disable); +bool ShowHideElements(HANDLE hDlg, uint32_t chk, uint32_t chkStore, uint32_t begin, uint32_t end); +void HideDialogItems(HANDLE hDlg, unsigned int itemFirst, unsigned int itemLast); +void UnhideDialogItems(HANDLE hDlg, unsigned int itemFirst, unsigned int itemLast); +void DisableDialogItems(HANDLE hDlg, unsigned int itemFirst, unsigned int itemLast); +void EnableDialogItems(HANDLE hDlg, unsigned int itemFirst, unsigned int itemLast); +uint64_t GetNumberItem(HANDLE hDlg, unsigned int itemNum); +std::wstring GetText(HANDLE hDlg, unsigned int itemNum); + +class FarDialog { + private: + FarDlgConstructor * fdc; + HANDLE hDlg; + public: + explicit FarDialog(FarDlgConstructor * data, FARWINDOWPROC dlgProc = 0, LONG_PTR param = 0); + ~FarDialog(); + int Run(void); + bool CreateChangeList(std::vector & chlst); + + std::wstring GetText(unsigned int itemNum); + const wchar_t * GetConstText(unsigned int itemNum); + int32_t GetInt32(unsigned int itemNum); + int64_t GetInt64(unsigned int itemNum); + int32_t GetInt32FromHex(unsigned int itemNum, bool prefix = true); + int64_t GetInt64FromHex(unsigned int itemNum, bool prefix = true); + bool GetCheck(unsigned int itemNum); + HANDLE GetDlg(void); +}; +#endif diff --git a/src/farpanel.cpp b/src/farpanel.cpp new file mode 100644 index 0000000..c8b6fe2 --- /dev/null +++ b/src/farpanel.cpp @@ -0,0 +1,109 @@ +#include "farpanel.h" +#include "lng.h" + +#include +#include +#include + +#include + +extern const char * LOG_FILE; +#define LOG_SOURCE_FILE "farpanel.cpp" + +FarPanel::FarPanel(): + index(NO_PANEL_INDEX), + data(nullptr) +{ + LOG_INFO("index NO_PANEL_INDEX\n"); +} + +FarPanel::FarPanel(uint32_t index_): + index(static_cast(index_)), + data(std::make_unique()) +{ + LOG_INFO("index %u\n", index); + FillPanelData(data.get(), index); +} + +FarPanel::~FarPanel() +{ + LOG_INFO("\n"); +} + +void FarPanel::GetOpenPluginInfo(struct OpenPluginInfo * info) +{ + LOG_INFO("index %u\n", index); + ReloadPanelString(data.get(), index); + *info = data->openInfo; +} + +const wchar_t * FarPanel::GetPanelTitle(void) +{ + ReloadPanelString(data.get(), index); + return data->openInfo.PanelTitle; +} + +int FarPanel::SetDirectory(const wchar_t *dir, int opMode) +{ + LOG_INFO("\n"); + return int(false); +} + +int FarPanel::DeleteFiles(struct PluginPanelItem *panelItem, int itemsNumber, int opMode) +{ + LOG_INFO("\n"); + return int(false); +} + +int FarPanel::ProcessEvent(int event, void *param) +{ + LOG_INFO("\n"); + return int(false); +} + +const wchar_t * FarPanel::GetPanelTitleKey(int key, unsigned int controlState) const +{ + if( !(key >= VK_F1 && key <= VK_F12) ) + return nullptr; + + auto keyNum = key - VK_F1; + + switch( controlState ) { + case 0: + return data->openInfo.KeyBar->Titles[keyNum]; + case PKF_SHIFT: + return data->openInfo.KeyBar->ShiftTitles[keyNum]; + case PKF_CONTROL: + return data->openInfo.KeyBar->CtrlTitles[keyNum]; + case PKF_ALT: + return data->openInfo.KeyBar->AltTitles[keyNum]; + case (PKF_CONTROL|PKF_SHIFT): + return data->openInfo.KeyBar->CtrlShiftTitles[keyNum]; + case (PKF_ALT|PKF_SHIFT): + return data->openInfo.KeyBar->AltShiftTitles[keyNum]; + case (PKF_CONTROL|PKF_ALT): + return data->openInfo.KeyBar->CtrlAltTitles[keyNum]; + }; + + return nullptr; +} + +bool FarPanel::IsPanelProcessKey(int key, unsigned int controlState) const +{ + return GetPanelTitleKey(key, controlState) != 0; +} + +void FarPanel::FreeFindData(struct PluginPanelItem * panelItem, int itemsNumber) +{ + LOG_INFO("\n"); + while( itemsNumber-- ) { + while( (panelItem+itemsNumber)->CustomColumnNumber-- ) + free((void *)(panelItem+itemsNumber)->CustomColumnData[(panelItem+itemsNumber)->CustomColumnNumber]); + free((void *)(panelItem+itemsNumber)->CustomColumnData); + + if( (panelItem+itemsNumber)->Flags & PPIF_USERDATA && (panelItem+itemsNumber)->UserData ) + free((void *)(panelItem+itemsNumber)->UserData); + + } + free((void *)panelItem); +} diff --git a/src/farpanel.h b/src/farpanel.h new file mode 100644 index 0000000..d0a4dc1 --- /dev/null +++ b/src/farpanel.h @@ -0,0 +1,54 @@ +#ifndef __FARPANEL_H__ +#define __FARPANEL_H__ + +#include +#include +#include "plugincfg.h" + +#define NO_PANEL_INDEX (PanelIndex)(-1) + +struct PanelData { + struct PanelMode panelModesArray[PanelModeMax]; + struct KeyBarTitles keyBar; + struct OpenPluginInfo openInfo; + PanelData() { + memset(panelModesArray, 0, sizeof(panelModesArray)); + memset(&keyBar, 0, sizeof(keyBar)); + memset(&openInfo, 0, sizeof(openInfo)); + openInfo.StructSize = sizeof(OpenPluginInfo); + openInfo.PanelModesArray = panelModesArray; + openInfo.PanelModesNumber = ARRAYSIZE(panelModesArray); + openInfo.KeyBar = &keyBar; + }; +}; + +class FarPanel: public PluginCfg { +private: + PanelIndex index; + std::unique_ptr data; +public: + virtual int ProcessKey(HANDLE hPlugin, int key, unsigned int controlState, bool & change) = 0; + virtual int GetFindData(struct PluginPanelItem **pPanelItem, int *pItemsNumber) = 0; + virtual void GetOpenPluginInfo(struct OpenPluginInfo * info); + virtual void FreeFindData(struct PluginPanelItem * panelItem, int itemsNumber); + virtual int SetDirectory(const wchar_t *dir, int opMode); + virtual int DeleteFiles(struct PluginPanelItem *panelItem, int itemsNumber, int opMode); + virtual int ProcessEvent(int event, void *param); + + virtual bool Valid(void) { return index != NO_PANEL_INDEX; }; + + const wchar_t * GetPanelTitle(void); + const wchar_t * GetPanelTitleKey(int key, unsigned int controlState = 0) const; + + OpenPluginInfo & GetOpenPluginInfo(void) { return data->openInfo; }; + typedef PanelMode PanelModes[PanelModeMax]; + PanelModes & GetPanelModesArray(void) { return data->panelModesArray; }; + + bool IsPanelProcessKey(int key, unsigned int controlState) const; + + FarPanel(uint32_t index); + FarPanel(); + virtual ~FarPanel(); +}; + +#endif /* __FARPANEL_H__ */ diff --git a/src/lng.h b/src/lng.h new file mode 100644 index 0000000..5247f3e --- /dev/null +++ b/src/lng.h @@ -0,0 +1,34 @@ +#ifndef __LNG_H__ +#define __LNG_H__ + +enum { + MNotUsed, + MEmptyString, + MProcessDiskMenuString, + MPluginConfigString, + + MPanelProcessTitle, + MFormatProcessPanel, + + MOk, + MCancel, + + MConfigPluginTitle, + MAddDisksMenu, + MAddToPluginsMenu, + MEnableLog, + + MConfigPluginSettings, + MConfigSaveSettings, + + ps_title_short, + + ps_cfg_prefix, + + MF4CPUSort, + + MMaxString +}; + + +#endif // __LNG_H__ diff --git a/src/plugin.cpp b/src/plugin.cpp new file mode 100644 index 0000000..e2c44ed --- /dev/null +++ b/src/plugin.cpp @@ -0,0 +1,114 @@ +#include +#include +#include +#include + +#include "plugin.h" + +#include + +#include + +#include +#include + +#include + +extern const char * LOG_FILE; +#define LOG_SOURCE_FILE "plugin.cpp" + +struct PluginStartupInfo Plugin::psi = {0}; +struct FarStandardFunctions Plugin::FSF = {0}; + +Plugin::Plugin(const PluginStartupInfo * info) +{ + assert( (unsigned int)info->StructSize >= sizeof(PluginStartupInfo) ); + assert( psi.StructSize == 0 ); + psi=*info; + + assert( (unsigned int)info->FSF->StructSize >= sizeof(FarStandardFunctions) ); + assert( FSF.StructSize == 0 ); + FSF=*info->FSF; + + psi.FSF=&FSF; + + cfg = new PluginCfg(); + + LOG_INFO("\n"); +} + +Plugin::~Plugin() +{ + LOG_INFO("\n"); + + panel.clear(); + + delete cfg; + cfg = nullptr; + + memset(&psi, 0, sizeof(psi)); + memset(&FSF, 0, sizeof(FSF)); +} + +int Plugin::Configure(int itemNumber) +{ + assert( cfg != 0 ); + return cfg->Configure(itemNumber); +} + +void Plugin::GetOpenPluginInfo(HANDLE hPlugin, struct OpenPluginInfo *info) +{ + LOG_INFO("GetOpenPluginInfo(hPlugin = %p)\n", hPlugin); + assert( hPlugin && hPlugin != INVALID_HANDLE_VALUE ); + static_cast(hPlugin)->GetOpenPluginInfo(info); +} + +void Plugin::GetPluginInfo(struct PluginInfo *info) +{ + LOG_INFO("\n"); + cfg->GetPluginInfo(info); +} + +int Plugin::GetFindData(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber) +{ + LOG_INFO("\n"); + return static_cast(hPlugin)->GetFindData(pPanelItem, pItemsNumber); +} + +void Plugin::FreeFindData(HANDLE hPlugin,struct PluginPanelItem * panelItem, int itemsNumber) +{ + LOG_INFO("\n"); + return static_cast(hPlugin)->FreeFindData(panelItem, itemsNumber); +} + +int Plugin::ProcessKey(HANDLE hPlugin,int key,unsigned int controlState) +{ + LOG_INFO("hPlugin: %p key 0x%08X VK_F2 0x%08X\n", hPlugin, key, VK_F2); + + bool redraw = false; + int res = static_cast(hPlugin)->ProcessKey(hPlugin, key, controlState, redraw); + + if( redraw ) { + LOG_INFO("Plugin::ProcessKey() redraw\n"); + psi.Control(hPlugin, FCTL_UPDATEPANEL, TRUE, 0); + psi.Control(hPlugin, FCTL_REDRAWPANEL, 0, 0); + } + return res; +} + +int Plugin::SetDirectory(HANDLE hPlugin, const wchar_t *dir, int opMode) +{ + LOG_INFO("\n"); + return static_cast(hPlugin)->SetDirectory(dir, opMode); +} + +int Plugin::DeleteFiles(HANDLE hPlugin, struct PluginPanelItem *panelItem, int itemsNumber, int opMode) +{ + LOG_INFO("\n"); + return static_cast(hPlugin)->DeleteFiles(panelItem, itemsNumber, opMode); +} + +int Plugin::ProcessEvent(HANDLE hPlugin,int event,void *param) +{ + return static_cast(hPlugin)->ProcessEvent(event, param); +} diff --git a/src/plugin.h b/src/plugin.h new file mode 100644 index 0000000..25a83ef --- /dev/null +++ b/src/plugin.h @@ -0,0 +1,48 @@ +#ifndef __PLUGIN_H__ +#define __PLUGIN_H__ + +#include "plugincfg.h" +#include "farpanel.h" + +class Plugin { + private: + + // copy and assignment not allowed + Plugin(const Plugin&) = delete; + void operator=(const Plugin&) = delete; + + protected: + + // Configuration + PluginCfg * cfg; + + // Panels + std::vector> panel; + + public: + + explicit Plugin(const PluginStartupInfo * info); + virtual ~Plugin(); + + // far2l backconnect + static struct PluginStartupInfo psi; + static struct FarStandardFunctions FSF; + + // First call + virtual HANDLE OpenFilePlugin(const wchar_t * name,const unsigned char * data, int dataSize, int opMode) = 0; + virtual HANDLE OpenPlugin(int openFrom, INT_PTR item) = 0; + virtual void ClosePlugin(HANDLE hPlugin) = 0; + + // far2l api + virtual int GetFindData(HANDLE hPlugin, struct PluginPanelItem **pPanelItem, int *pItemsNumber); + virtual void FreeFindData(HANDLE hPlugin, struct PluginPanelItem * PanelItem, int ItemsNumber); + virtual void GetPluginInfo(struct PluginInfo *info); + virtual void GetOpenPluginInfo(HANDLE hPlugin, struct OpenPluginInfo *info); + virtual int SetDirectory(HANDLE hPlugin, const wchar_t *dir, int opMode); + virtual int DeleteFiles(HANDLE hPlugin, struct PluginPanelItem *panelItem, int itemsNumber, int opMode); + virtual int ProcessKey(HANDLE hPlugin,int key,unsigned int controlState); + virtual int ProcessEvent(HANDLE hPlugin,int event,void *param); + virtual int Configure(int itemNumber); +}; + +#endif /* __PLUGIN_H__ */ diff --git a/src/plugincfg.cpp b/src/plugincfg.cpp new file mode 100644 index 0000000..1fee5b3 --- /dev/null +++ b/src/plugincfg.cpp @@ -0,0 +1,422 @@ +#include "plugincfg.h" +#include "procplugin.h" +#include "lng.h" +#include "fardialog.h" +#include "farpanel.h" + +#include +#include + + +#include +#include + +#include + +#define LOG_SOURCE_FILE "plugincfg.cpp" +#define LOG_MAX_PATH 256 + +static char initial_log[LOG_MAX_PATH] = {'/','t','m','p','/','f','a','r','2','l','.','p','r','o','c','e','s','s','.','l','o','g',0}; +const char * LOG_FILE = initial_log; +//static_assert( sizeof("/dev/null") < LOG_MAX_PATH ); + +#define INI_LOCATION InMyConfig("plugins/process/config.ini") +#define INI_SECTION "Settings" +#define DEFAULT_PREFIX L"process" + +const char * PluginCfg::GetPanelName(PanelIndex index) const +{ + static const char * names[] = { + "Process", // ProcessPanelIndex, + "max" // MaxPanelIndex + }; + assert( index < (ARRAYSIZE(names)-1) ); + return names[index]; +} + +size_t PluginCfg::init = 0; +std::map PluginCfg::def = {\ + {ProcessPanelIndex, { + L"N,C0,C1,C2,C3,SF", + L"0,8,3,5,6,10", + // module N + // pid C0 + // priority C1 + // nice C2 + // cpu C3 + // memory SF + {L"N,C0,C1,C2,C3,SF", L"N,C0,C1,C2,C3,SF"}, + {L"0,8,3,5,6,10", L"0,8,3,5,6,10"}, + {{L"module",L"pid",L"priority",L"nice",L"cpu",L"memory", 0}, {L"module",L"pid",L"priority",L"nice",L"cpu",L"memory",0}}, + {0,MEmptyString,0,0,MEmptyString,MEmptyString,MEmptyString,0,0,0,0,0}, + {MEmptyString,MEmptyString,MEmptyString,MEmptyString,MEmptyString,MEmptyString,MEmptyString,MEmptyString,MEmptyString,MEmptyString,MEmptyString,MEmptyString}, + {0,0,0,MF4CPUSort,0,0,0,0,0,0,0,0}, + MPanelProcessTitle, + MFormatProcessPanel, + OPIF_USEFILTER|OPIF_USEHIGHLIGHTING|OPIF_SHOWPRESERVECASE|OPIF_ADDDOTS, + SM_NUMLINKS, 0 + }}, + }; + +bool PluginCfg::logEnable = true; +bool PluginCfg::processAddToDisksMenu = false; +bool PluginCfg::processAddToPluginsMenu = false; + +void PluginCfg::ReloadPanelKeyBar(struct PanelData * data, PanelIndex index) +{ + assert( def.find(index) != def.end() ); + auto & cfg = def[index]; + auto keyBar = &data->keyBar.Titles[0]; + for( auto item : cfg.keyBarTitles ) { + if( item && item < MMaxString ) + *keyBar = (TCHAR*)GetMsg(item); + keyBar++; + } + + keyBar = &data->keyBar.ShiftTitles[0]; + for( auto item : cfg.keyBarShiftTitles ) { + if( item && item < MMaxString ) + *keyBar = (TCHAR*)GetMsg(item); + keyBar++; + } + + keyBar = &data->keyBar.CtrlTitles[0]; + for( auto item : cfg.keyBarCtrlTitles ) { + if( item && item < MMaxString ) + *keyBar = (TCHAR*)GetMsg(item); + keyBar++; + } + + constexpr static wchar_t * empty_string = const_cast(L""); + constexpr static wchar_t * defAltkeys[12] = {0,0,empty_string,empty_string,empty_string,empty_string,empty_string,0,0,empty_string,empty_string,empty_string}; + constexpr static wchar_t * defkeys[12] = {empty_string,empty_string,empty_string,empty_string,empty_string,empty_string,empty_string,empty_string,empty_string,empty_string,empty_string,empty_string}; + memmove(data->keyBar.AltTitles, defAltkeys, sizeof(defAltkeys)); + memmove(data->keyBar.CtrlShiftTitles, defkeys, sizeof(defkeys)); + memmove(data->keyBar.AltShiftTitles, defkeys, sizeof(defkeys)); + memmove(data->keyBar.CtrlAltTitles, defkeys, sizeof(defkeys)); +} + +void PluginCfg::ReloadPanelString(struct PanelData * data, PanelIndex index) +{ + ReloadPanelKeyBar(data, index); + auto & cfg = def[index]; + data->openInfo.Format=(TCHAR*)GetMsg(cfg.format); + data->openInfo.PanelTitle=(TCHAR*)GetMsg(cfg.panelTitle); +} + +void PluginCfg::FillPanelData(struct PanelData * data, PanelIndex index) +{ + assert( def.find(index) != def.end() ); + + auto & cfg = def[index]; + auto & nmodes = data->panelModesArray; + for( size_t i =0; i < ARRAYSIZE(nmodes); i++ ) { + nmodes[i].FullScreen = FALSE; + nmodes[i].DetailedStatus = 0; + nmodes[i].AlignExtensions = 0; + nmodes[i].CaseConversion = TRUE; + nmodes[i].StatusColumnTypes = cfg.statusColumnTypes; + nmodes[i].StatusColumnWidths = cfg.statusColumnWidths; + } + + nmodes[4].ColumnTypes = cfg.columnTypes[0]; + nmodes[4].ColumnWidths = cfg.columnWidths[0]; + // TODO + nmodes[4].ColumnTitles = cfg.columnTitles[0]; + + nmodes[5].ColumnTypes = cfg.columnTypes[1]; + nmodes[5].ColumnWidths = cfg.columnWidths[1]; + // TODO + nmodes[5].ColumnTitles = cfg.columnTitles[1]; + nmodes[5].FullScreen = TRUE; + + data->openInfo.Flags = cfg.flags; + data->openInfo.CurDir=_T(""); + data->openInfo.StartPanelMode=_T('4'); + data->openInfo.StartSortMode = cfg.startSortMode; + data->openInfo.StartSortOrder = cfg.startSortOrder; + + ReloadPanelString(data, index); +} + +PluginCfg::PluginCfg() +{ + LOG_INFO("init %d\n", init); + + if( init++ ) + return; + + LOG_INFO("=== INIT ===\n"); + + { + KeyFileReadSection kfr(INI_LOCATION, INI_SECTION); + + processAddToDisksMenu = (bool)kfr.GetInt("processAddToDisksMenu", true); + processAddToPluginsMenu = (bool)kfr.GetInt("processAddToPluginsMenu", true); + + prefix = kfr.GetString("prefix", DEFAULT_PREFIX); + + logEnable = (bool)kfr.GetInt("logEnable", true); + if( logEnable ) { + std::string logfile = kfr.GetString("logfile", initial_log); + if( logfile.size() < (LOG_MAX_PATH-1) && logfile.size() >= sizeof("/a") ) + memmove(initial_log, logfile.c_str(), logfile.size()+1); + } else + memmove(initial_log, "/dev/null", sizeof("/dev/null")); + } + + KeyFileReadHelper kfrh(INI_LOCATION); + for( auto & [index, item] : def ) { + const char * name = GetPanelName(index); + + item.statusColumnTypes = wcsdup(kfrh.GetString(name, "statusColumnTypes", item.statusColumnTypes).c_str()); + item.statusColumnWidths = wcsdup(kfrh.GetString(name, "statusColumnWidths", item.statusColumnWidths).c_str()); + + item.columnTypes[0] = wcsdup(kfrh.GetString(name, "columnTypes4", item.columnTypes[0]).c_str()); + item.columnTypes[1] = wcsdup(kfrh.GetString(name, "columnTypes5", item.columnTypes[1]).c_str()); + + item.columnWidths[0] = wcsdup(kfrh.GetString(name, "columnWidths4", item.columnWidths[0]).c_str()); + item.columnWidths[1] = wcsdup(kfrh.GetString(name, "columnWidths5", item.columnWidths[1]).c_str()); + + std::string field_prefix("title4_"); + uint32_t offset = 0; + for( auto & title: item.columnTitles[0] ) { + if( title ) { + std::string field = field_prefix + std::to_string(offset); + title = wcsdup(kfrh.GetString(name, field.c_str(), title).c_str()); + } + offset++; + } + + field_prefix = "title5_"; + offset = 0; + for( auto & title: item.columnTitles[1] ) { + if( title ) { + std::string field = field_prefix + std::to_string(offset); + title = wcsdup(kfrh.GetString(name, field.c_str(), title).c_str()); + } + offset++; + } + } +} + +void PluginCfg::SaveConfig(void) const +{ + LOG_INFO("=== Save config ===\n"); + + KeyFileHelper kfh(INI_LOCATION); + for( auto & [index, item] : def ) { + const char * name = GetPanelName(index); + kfh.SetString(name, "statusColumnTypes", item.statusColumnTypes); + kfh.SetString(name, "statusColumnWidths", item.statusColumnWidths); + kfh.SetString(name, "columnTypes4", item.columnTypes[0]); + kfh.SetString(name, "columnTypes5", item.columnTypes[1]); + kfh.SetString(name, "columnWidths4", item.columnWidths[0]); + kfh.SetString(name, "columnWidths5", item.columnWidths[1]); + + std::string field_prefix("title4_"); + uint32_t offset = 0; + for( auto & title: item.columnTitles[0] ) { + if( title ) { + std::string field = field_prefix + std::to_string(offset); + kfh.SetString(name, field.c_str(), title); + } + offset++; + } + + field_prefix = "title5_"; + offset = 0; + for( auto & title: item.columnTitles[1] ) { + if( title ) { + std::string field = field_prefix + std::to_string(offset); + kfh.SetString(name, field.c_str(), title); + } + offset++; + } + } + + kfh.SetInt(INI_SECTION, "processAddToDisksMenu", processAddToDisksMenu); + kfh.SetInt(INI_SECTION, "processAddToPluginsMenu", processAddToPluginsMenu); + + std::string _logfile(LOG_FILE); + kfh.SetString(INI_SECTION, "logfile", _logfile); + kfh.SetInt(INI_SECTION, "logEnable", logEnable); + kfh.SetString(INI_SECTION, "prefix", prefix.c_str()); + kfh.Save(); +} + +PluginCfg::~PluginCfg() +{ + LOG_INFO("init %d\n", init); + + if( --init ) + return; + + LOG_INFO("=== FREE ===\n"); + + for( auto & [index, item] : def ) { + free((void *)item.statusColumnTypes); + free((void *)item.statusColumnWidths); + free((void *)item.columnTypes[0]); + free((void *)item.columnTypes[1]); + free((void *)item.columnWidths[0]); + free((void *)item.columnWidths[1]); + + for( auto & title: item.columnTitles[0] ) { + if( title ) + free((void *)title); + } + for( auto & title: item.columnTitles[1] ) { + if( title ) + free((void *)title); + } + } +} + +void PluginCfg::GetPluginInfo(struct PluginInfo *info) +{ + info->StructSize = sizeof(PluginInfo); + info->Flags = 0; + + static const wchar_t *diskMenuStrings[2]; + static const wchar_t *pluginMenuStrings[2]; + static const wchar_t *pluginConfigStrings[1]; + + diskMenuStrings[0] = GetMsg(MProcessDiskMenuString); + + info->DiskMenuStrings = diskMenuStrings; + info->DiskMenuStringsNumber = (int)processAddToDisksMenu; + + pluginMenuStrings[0] = GetMsg(MProcessDiskMenuString); + info->PluginMenuStrings = pluginMenuStrings; + info->PluginMenuStringsNumber = (int)processAddToPluginsMenu; + + pluginConfigStrings[0] = GetMsg(MPluginConfigString); + info->PluginConfigStrings = pluginConfigStrings; + info->PluginConfigStringsNumber = ARRAYSIZE(pluginConfigStrings); + + info->CommandPrefix = prefix.c_str(); +} + +static const int DIALOG_WIDTH = 78; + +enum { + WinCfgCaptionIndex, + WinCfgAddDiskMenuIndex, + WinCfgAddPluginsMenuIndex, + WinCfgSeparator1Index, + WinCfgEanbleLogIndex, + WinCfgEanbleLogStoreIndex, + WinCfgEanbleLogEditIndex, + WinCfgSeparator2Index, + WinCfgConfigPrefixTextIndex, + WinCfgConfigPrefixEditIndex, + WinCfgConfigSaveSettingsCheckboxIndex, + WinCfgMaxIndex +}; + +LONG_PTR WINAPI CfgDialogProc(HANDLE hDlg, int msg, int param1, LONG_PTR param2) +{ + if( msg == DN_DRAWDLGITEM ) { + if( param1 == WinCfgEanbleLogIndex ) { + ShowHideElements(hDlg, + WinCfgEanbleLogIndex, + WinCfgEanbleLogStoreIndex, + WinCfgEanbleLogEditIndex, + WinCfgEanbleLogEditIndex); + } + } + return Plugin::psi.DefDlgProc(hDlg, msg, param1, param2); +} + +int PluginCfg::Configure(int itemNumber) +{ + LOG_INFO("itemNumber = %d\n", itemNumber); + bool change = false; + + static const DlgConstructorItem dci[] = { + {DI_DOUBLEBOX,false, DEFAUL_X_START, DIALOG_WIDTH-4, 0, {.lngIdstring = MConfigPluginSettings}}, + {DI_CHECKBOX, true, 5, 0, 0, {.lngIdstring = MAddDisksMenu}}, + {DI_CHECKBOX, false, 40, 0, 0, {.lngIdstring = MAddToPluginsMenu}}, + {DI_TEXT, true, 5, 0, DIF_BOXCOLOR|DIF_SEPARATOR, {0}}, + {DI_CHECKBOX, true, 5, 0, 0, {.lngIdstring = MEnableLog}}, + /* Store */{DI_CHECKBOX, false, 80, 0, DIF_HIDDEN, {0}}, + {DI_EDIT, false, 21, DIALOG_WIDTH-6, 0, {0}}, + + + {DI_TEXT, true, 5, 0, 0, {0}}, + {DI_TEXT, true, 5, 0, 0, {.lngIdstring = ps_cfg_prefix}}, + {DI_EDIT, false, 14, 35/*DIALOG_WIDTH-6*/, 0, {0}}, + + {DI_CHECKBOX, false, 33, 0, 0, {.lngIdstring = MConfigSaveSettings}}, + {DI_ENDDIALOG, 0} + }; + + FarDlgConstructor fdc(&dci[0]); + + fdc.SetSelected(WinCfgAddDiskMenuIndex, processAddToDisksMenu); + fdc.SetSelected(WinCfgAddPluginsMenuIndex, processAddToPluginsMenu); + + fdc.SetSelected(WinCfgEanbleLogIndex, logEnable); + + std::string _logfile(LOG_FILE); + std::wstring logfile(_logfile.begin(), _logfile.end()); + fdc.SetText(WinCfgEanbleLogEditIndex, logfile.c_str()); + fdc.SetX(WinCfgEanbleLogEditIndex, wcslen(GetMsg(MEnableLog))+9); + + fdc.SetText(WinCfgConfigPrefixEditIndex, prefix.c_str()); + fdc.SetX(WinCfgConfigPrefixEditIndex, wcslen(GetMsg(ps_cfg_prefix))+6); + + fdc.SetX(WinCfgConfigSaveSettingsCheckboxIndex, DIALOG_WIDTH - 8 - wcslen(GetMsg(MConfigSaveSettings))); + + if( !logEnable ) + fdc.OrFlags(WinCfgEanbleLogEditIndex, DIF_DISABLE); + + auto offSuffix = fdc.AppendOkCancel(); + + fdc.SetDefaultButton(offSuffix + WinSuffixOkIndex); + fdc.SetFocus(offSuffix + WinSuffixOkIndex); + + fdc.SetHelpTopic(L"Config"); + + FarDialog dlg(&fdc, CfgDialogProc, (LONG_PTR)this); + + if( (dlg.Run() - offSuffix) == WinSuffixOkIndex ) { + + std::vector chlst; + change |= dlg.CreateChangeList(chlst); + + if( !change ) + return false; + + for( auto & item : chlst ) { + switch(item.itemNum) { + case WinCfgAddDiskMenuIndex: + processAddToDisksMenu = bool(item.newVal.Selected); + break; + case WinCfgAddPluginsMenuIndex: + processAddToPluginsMenu = bool(item.newVal.Selected); + break; + case WinCfgEanbleLogEditIndex: + logfile = item.newVal.ptrData; + if( logfile.size() < (LOG_MAX_PATH-1) && logfile.size() >= sizeof("/a") ) { + _logfile = Wide2MB( logfile.c_str() ); + memmove(initial_log, _logfile.c_str(), _logfile.size()+1); + } + break; + case WinCfgEanbleLogIndex: + logEnable = bool(item.newVal.Selected); + if( !logEnable ) + memmove(initial_log, "/dev/null", sizeof("/dev/null")); + break; + case WinCfgConfigPrefixEditIndex: + prefix = item.newVal.ptrData; + break; + case WinCfgConfigSaveSettingsCheckboxIndex: + SaveConfig(); + break; + }; + } + } + return change; +} diff --git a/src/plugincfg.h b/src/plugincfg.h new file mode 100644 index 0000000..3a18be2 --- /dev/null +++ b/src/plugincfg.h @@ -0,0 +1,76 @@ +#ifndef __CONFIGPLUGIN_H__ +#define __CONFIGPLUGIN_H__ + +#include +#include +#include +#include +#include "lng.h" +#include "farapi.h" + +enum { + PanelModeBrief, + PanelModeMedium, + PanelModeFull, + PanelModeWide, + PanelModeDetailed, + PanelModeDiz, + PanelModeLongDiz, + PanelModeOwners, + PanelModeLinks, + PanelModeAlternative, + PanelModeMax, +}; + +typedef struct { + const wchar_t * statusColumnTypes; + const wchar_t * statusColumnWidths; + const wchar_t * columnTypes[2]; + const wchar_t * columnWidths[2]; + const wchar_t * columnTitles[2][15]; + uint32_t keyBarTitles[12]; + uint32_t keyBarShiftTitles[12]; + uint32_t keyBarCtrlTitles[12]; + uint32_t panelTitle; + uint32_t format; + uint32_t flags; + int startSortMode; + int startSortOrder; +} CfgDefaults; + +typedef enum { + ProcessPanelIndex, + MaxPanelIndex +} PanelIndex; + +class PluginCfg : public FarApi { + + private: + static std::map def; + static size_t init; + + const char * GetPanelName(PanelIndex index) const; + + static bool logEnable; + + friend LONG_PTR WINAPI CfgDialogProc(HANDLE hDlg, int msg, int param1, LONG_PTR param2); + + void SaveConfig(void) const; + + public: + explicit PluginCfg(); + ~PluginCfg(); + + static bool processAddToDisksMenu; + static bool processAddToPluginsMenu; + std::wstring prefix; + + void FillPanelData(struct PanelData * data, PanelIndex index); + void ReloadPanelKeyBar(struct PanelData * data, PanelIndex index); + void ReloadPanelString(struct PanelData * data, PanelIndex index); + + void GetPluginInfo(struct PluginInfo *info); + int Configure(int itemNumber); +}; + +#endif /* __CONFIGPLUGIN_H__ */ diff --git a/src/process/process.cpp b/src/process/process.cpp new file mode 100644 index 0000000..bf6b794 --- /dev/null +++ b/src/process/process.cpp @@ -0,0 +1,248 @@ +#include "process.h" + +#include +#include +#include + +#include +#include + +#ifndef MAIN_PROCESS +extern const char * LOG_FILE; +#else +const char * LOG_FILE = ""; +#endif + +#define LOG_SOURCE_FILE "process.cpp" + +void Process::FreeFileData(char * buf) const +{ + ::FreeFileData(buf); +} + +char * Process::GetFileData(const char * fmt, pid_t _ppid, pid_t _tpid, ssize_t *readed) const +{ + char path[sizeof("/proc/4294967296/task/4294967296/coredump_filter")]; + if( snprintf(path, sizeof(path), fmt, _ppid, _tpid) < 0 ) { + LOG_ERROR("snprintf(fmt=\"%s\",_ppid=%u, _tpid=%u) ... error (%s)\n", fmt, _ppid, _tpid, errorname(errno)); + return 0; + } + + return ::GetFileData(path, 0); +} + +/*static unsigned long long AdjustTime(unsigned long long t) +{ + static int hz = 0; + + if( !hz ) + hz = sysconf(_SC_CLK_TCK); + + if( !hz ) + hz = 100; + + return t * 100 / hz; +}*/ + + +void Process::Update() +{ + /* fill in default values for older kernels */ + processor = 0; + rtprio = -1; + sched = -1; + nlwp = 0; + + char * buf = GetFileData("/proc/%u/stat", pid, 0, 0); + if( !buf ) + return; + + valid = false; + do { + char *s = strrchr(buf, '(')+1; + if( !s ) break; + char *s2 = strrchr(s, ')'); + if( !s2 || !s2[1]) break; + name = std::string(s,strrchr(s, ')')); + + s = s2 + 2; // skip ") " + + if( sscanf(s, + "%c " // state + "%d %d %d %d %d " // ppid, pgrp, sid, tty_nr, tty_pgrp + "%lu %lu %lu %lu %lu " // flags, min_flt, cmin_flt, maj_flt, cmaj_flt + "%llu %llu %llu %llu " // utime, stime, cutime, cstime + "%d %d " // priority, nice + "%d " // num_threads + "%lu " // 'alarm' == it_real_value (obsolete, always 0) + "%llu " // start_time + "%lu " // vsize + "%lu " // rss + "%lu %lu %lu %lu %lu %lu " // rsslim, start_code, end_code, start_stack, esp, eip + "%*s %*s %*s %*s " // pending, blocked, sigign, sigcatch <=== DISCARDED + "%lu %*u %*u " // 0 (former wchan), 0, 0 <=== Placeholders only + "%d %d " // exit_signal, task_cpu + "%d %d " // rt_priority, policy (sched) + "%llu %llu %llu", // blkio_ticks, gtime, cgtime + &state, + &ppid, &pgrp, &session, &tty, &tpgid, + &flags, &min_flt, &cmin_flt, &maj_flt, &cmaj_flt, + &utime, &stime, &cutime, &cstime, + &priority, &nice, + &nlwp, + &alarm, + &start_time, + &vsize, + &rss, + &rss_rlim, &start_code, &end_code, &start_stack, &kstk_esp, &kstk_eip, + /* signal, blocked, sigignore, sigcatch, */ /* can't use */ + &wchan, /* &nswap, &cnswap, */ /* nswap and cnswap dead for 2.4.xx and up */ + /* -- Linux 2.0.35 ends here -- */ + &exit_signal, &processor, /* 2.2.1 ends with "exit_signal" */ + /* -- Linux 2.2.8 to 2.5.17 end here -- */ + &rtprio, &sched, /* both added to 2.5.18 */ + &blkio_tics, >ime, &cgtime) < 0 ) { + LOG_ERROR("sscanf(%s) ... error (%s)\n", buf, errorname(errno)); + break; + } + + if( flags & PF_KTHREAD ) { + name = "["+name+"]"; + } + + if( !ct.total_period ) + percent_cpu = 0.0F; + else { + percent_cpu = (ct.period < 1E-6) ? 0.0F : ((((double)(utime + stime - lasttimes)) / ct.total_period) * 100.0); + percent_cpu = CLAMP(percent_cpu, 0.0F, ct.activeCPUs * 100.0F); + LOG_INFO("buf: %s\n", buf); + LOG_INFO("utime + stime: %ld\n", utime + stime); + LOG_INFO("lasttimes: %ld\n", lasttimes); + LOG_INFO("percent_cpu: %.10f%%\n", percent_cpu); + } + + lasttimes = utime + stime; + + LOG_INFO("set lasttimes to %d\n", lasttimes); + + valid = true; + + } while(0); + + nlwp = 1; + + FreeFileData(buf); + + buf = GetFileData("/proc/%u/statm", pid, 0, 0); + if( !buf ) + return; + + long int dummy, dummy2; + + LOG_INFO("buf: %s\n", buf); + + /*int r = */ sscanf(buf, "%ld %ld %ld %ld %ld %ld %ld", + &m_virt, + &m_resident, + &m_share, + &m_trs, + &dummy, /* unused since Linux 2.6; always 0 */ + &m_drs, + &dummy2); /* unused since Linux 2.6; always 0 */ + + //if( r == 7 ) { + //m_virt *= pageSizeKB; + //m_resident *= pageSizeKB; + //} + + FreeFileData(buf); + + Log(); + + return; +} + +Process::Process(pid_t pid_, CPUTimes & ct_): + pid(pid_), + ct(ct_) +{ + lasttimes = 0; + pageSize = sysconf(_SC_PAGESIZE); + if( pageSize == -1 ) { + LOG_ERROR("Cannot get pagesize by sysconf(_SC_PAGESIZE) ... error (%s)\n", errorname(errno)); + pageSize = DEFAULT_PAGE_SIZE; + } + pageSizeKB = pageSize / ONE_K; + +// LOG_INFO("id=%u\n", pid); + Update(); +}; + +CPUTimes dummy_ct_; + +Process::Process(pid_t pid_): + pid(pid_), + ct(dummy_ct_) +{ + valid = false; +} + +Process::~Process() +{ +// LOG_INFO("id=%u\n", pid); +}; + +void Process::Log(void) const +{ + LOG_INFO("name: %s\n", name.c_str()); + LOG_INFO("state: %c\n", state); + LOG_INFO("ppid: %d, pgrp: %d, session: %d, tty: %d, tpgid: %d\n", ppid, pgrp, session, tty, tpgid); + LOG_INFO("flags: 0x%08X, min_flt: %d, cmin_flt: %d, maj_flt: %d, cmaj_flt: %d\n", flags, min_flt, cmin_flt, maj_flt, cmaj_flt); + LOG_INFO("utime %llu, stime %llu, cutime %llu, cstime %llu\n", utime, stime, cutime, cstime); + LOG_INFO("priority: %d, nice: %d\n", priority, nice); + LOG_INFO("pageSize: %d, pageSizeKB: %d\n", pageSize, pageSizeKB); + LOG_INFO("m_virt: %d, m_resident: %d\n", m_virt, m_resident); +} + +bool Process::Kill(void) const +{ + auto buf = std::make_unique(MAX_CMD_LEN+1); + if( (snprintf(buf.get(), MAX_CMD_LEN+1, "kill %d", pid)) < 0 ) + return false; + return Exec(buf.get()) == 0 ? true:RootExec(buf.get()) == 0; + +} + +#ifdef MAIN_PROCESS + +int RootExec(const char * cmd) +{ + std::string _cmd("sudo /bin/sh -c \'"); + _cmd += cmd; + _cmd += "'"; + LOG_INFO("Try exec \"%s\"\n", _cmd.c_str()); + return system(_cmd.c_str()); +} + +int Exec(const char * cmd) +{ + std::string _cmd("/bin/sh -c \'"); + _cmd += cmd; + _cmd += "'"; + LOG_INFO("Try exec \"%s\"\n", _cmd.c_str()); + return system(_cmd.c_str()); +} + +int main(int argc, char * argv[]) +{ + CPUTimes ct = {0}; + GetCPUTimes(&ct); + Process proc = Process(getpid(), ct); + proc.Log(); + for(int i=0; i< 10000; i++) + proc.FreeFileData(proc.GetFileData("/proc/%u/stat", getpid(), 0, 0)); + GetCPUTimes(&ct); + proc.Update(); + return 0; +} +#endif //MAIN_PROCESS diff --git a/src/process/process.h b/src/process/process.h new file mode 100644 index 0000000..0c23c0e --- /dev/null +++ b/src/process/process.h @@ -0,0 +1,269 @@ +#ifndef __PROCESS_H__ +#define __PROCESS_H__ + +#include +#include +#include +#include +#include + +#include + +#ifndef MINIMUM +#define MINIMUM(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAXIMUM +#define MAXIMUM(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef CLAMP +#define CLAMP(x, low, high) (assert((low) <= (high)), ((x) > (high)) ? (high) : MAXIMUM(x, low)) +#endif + +#ifndef DEFAULT_PAGE_SIZE +#define DEFAULT_PAGE_SIZE 4096 +#endif + +#ifndef ONE_K +#define ONE_K 1024UL +#endif + +#ifndef MAX_CMD_LEN +#define MAX_CMD_LEN 1024 +#endif + +#ifndef PF_KTHREAD +#define PF_KTHREAD 0x00200000 +#endif + +extern int RootExec(const char * cmd); +extern int Exec(const char * cmd); + +struct Process { + + pid_t pid; + CPUTimes & ct; + + unsigned long long lasttimes; + + int pageSize; + int pageSizeKB; + + + std::string name; + + float percent_cpu; + + /* Total program size (in kilobytes) */ + long m_virt; + + /* Resident set size (in kilobytes) */ + long m_resident; + + long m_share; + long m_trs; + long m_drs; + + + + //////////////////////////////////////////////////////////////////// + + + long m_pss; + long m_swap; + long m_psswp; + long m_lrs; + + pid_t ppid; // stat,status pid of parent process + + pid_t tid; // (special) task id, the POSIX thread ID (see also: tgid) + + // ////////////////////////////////////////////////////////////////// + // Namespace Particulars //////////////////////////////////////////// + + enum namespace_type { + PROCPS_NS_CGROUP, + PROCPS_NS_IPC, + PROCPS_NS_MNT, + PROCPS_NS_NET, + PROCPS_NS_PID, + PROCPS_NS_TIME, + PROCPS_NS_USER, + PROCPS_NS_UTS, + PROCPS_NS_COUNT // total namespaces (fencepost) + }; + + struct procps_ns { + unsigned long ns[PROCPS_NS_COUNT]; + }; + + unsigned long long + utime, // stat user-mode CPU time accumulated by process + stime, // stat kernel-mode CPU time accumulated by process + cutime, // stat cumulative utime of process and reaped children + cstime, // stat cumulative stime of process and reaped children + start_time, // stat start time of process -- seconds since system boot + blkio_tics, // stat time spent waiting for block IO + gtime, // stat guest time of the task in jiffies + cgtime; // stat guest time of the task children in jiffies + + + char state; // stat,status single-char code for process state (S=sleeping) + + int // next 3 fields are NOT filled in by readproc + pcpu, // stat (special) elapsed tics for %CPU usage calculation + maj_delta, // stat (special) major page faults since last update + min_delta; // stat (special) minor page faults since last update + + char + // Linux 2.1.7x and up have 64 signals. Allow 64, plus '\0' and padding. + signal[18], // status mask of pending signals + blocked[18], // status mask of blocked signals + sigignore[18], // status mask of ignored signals + sigcatch[18], // status mask of caught signals + _sigpnd[18]; // status mask of PER TASK pending signals + + unsigned long + start_code, // stat address of beginning of code segment + end_code, // stat address of end of code segment + start_stack, // stat address of the bottom of stack for the process + kstk_esp, // stat kernel stack pointer + kstk_eip, // stat kernel instruction pointer + wchan, // stat (special) address of kernel wait channel proc is sleeping in + rss, // stat identical to 'resident' + alarm; // stat ? + + int + priority, // stat kernel scheduling priority + nice; // stat standard unix nice level of process + unsigned long + // the next 7 members come from /proc/#/statm + size, // statm total virtual memory (as # pages) + resident, // statm resident non-swapped memory (as # pages) + share, // statm shared (mmap'd) memory (as # pages) + trs, // statm text (exe) resident set (as # pages) + lrs, // statm library resident set (always 0 w/ 2.6) + drs, // statm data+stack resident set (as # pages) + dt; // statm dirty pages (always 0 w/ 2.6) + + unsigned long + vm_size, // status equals 'size' (as kb) + vm_lock, // status locked pages (as kb) + vm_rss, // status equals 'rss' and/or 'resident' (as kb) + vm_rss_anon, // status the 'anonymous' portion of vm_rss (as kb) + vm_rss_file, // status the 'file-backed' portion of vm_rss (as kb) + vm_rss_shared, // status the 'shared' portion of vm_rss (as kb) + vm_data, // status data only size (as kb) + vm_stack, // status stack only size (as kb) + vm_swap, // status based on linux-2.6.34 "swap ents" (as kb) + vm_exe, // status equals 'trs' (as kb) + vm_lib, // status total, not just used, library pages (as kb) + vsize, // stat number of pages of virtual memory ... + rss_rlim, // stat resident set size limit? + flags, // stat kernel flags for the process + min_flt, // stat number of minor page faults since process start + maj_flt, // stat number of major page faults since process start + cmin_flt, // stat cumulative min_flt of process and child processes + cmaj_flt, // stat cumulative maj_flt of process and child processes + rchar, // io characters read + wchar, // io characters written + syscr, // io number of read I/O operations + syscw, // io number of write I/O operations + read_bytes, // io number of bytes fetched from the storage layer + write_bytes, // io number of bytes sent to the storage layer + cancelled_write_bytes, // io number of bytes truncating pagecache + smap_Rss, // smaps_rollup mapping currently resident in RAM + smap_Pss, // " Rss divided by total processes sharing it + smap_Pss_Anon, // " proportional share of 'anonymous' memory + smap_Pss_File, // " proportional share of 'file' memory + smap_Pss_Shmem, // " proportional share of 'shmem' memory + smap_Shared_Clean, // " unmodified shared memory + smap_Shared_Dirty, // " altered shared memory + smap_Private_Clean, // " unmodified private memory + smap_Private_Dirty, // " altered private memory + smap_Referenced, // " memory marked as referenced/accessed + smap_Anonymous, // " memory not belonging to any file + smap_LazyFree, // " memory marked by madvise(MADV_FREE) + smap_AnonHugePages, // " memory backed by transparent huge pages + smap_ShmemPmdMapped, // " shmem/tmpfs memory backed by huge pages + smap_FilePmdMapped, // " file memory backed by huge pages + smap_Shared_Hugetlb, // " hugetlbfs backed memory *not* counted in Rss/Pss + smap_Private_Hugetlb, // " hugetlbfs backed memory *not* counted in Rss/Pss + smap_Swap, // " swapped would-be-anonymous memory (includes swapped out shmem) + smap_SwapPss, // " the proportional share of 'Swap' (excludes swapped out shmem) + smap_Locked; // " memory amount locked to RAM + + char + *environ, // (special) environment as string (/proc/#/environ) + *cmdline, // (special) command line as string (/proc/#/cmdline) + *cgroup, // (special) cgroup as string (/proc/#/cgroup) + *cgname, // (special) name portion of above (if possible) + *supgid, // status supplementary gids as comma delimited str + *supgrp, // supp grp names as comma delimited str, derived from supgid + **environ_v, // (special) environment string vectors (/proc/#/environ) + **cmdline_v, // (special) command line string vectors (/proc/#/cmdline) + **cgroup_v; // (special) cgroup string vectors (/proc/#/cgroup) + + char + *euser, // stat(),status effective user name + *ruser, // status real user name + *suser, // status saved user name + *fuser, // status filesystem user name + *rgroup, // status real group name + *egroup, // status effective group name + *sgroup, // status saved group name + *fgroup, // status filesystem group name + *cmd; // stat,status basename of executable file in call to exec(2) + + int + rtprio, // stat real-time priority + sched, // stat scheduling class + pgrp, // stat process group id + session, // stat session id + nlwp, // stat,status number of threads, or 0 if no clue + tgid, // (special) thread group ID, the POSIX PID (see also: tid) + tty; // stat full device number of controlling terminal + /* FIXME: int uids & gids should be uid_t or gid_t from pwd.h */ + uid_t euid; gid_t egid; // stat(),status effective + uid_t ruid; gid_t rgid; // status real + uid_t suid; gid_t sgid; // status saved + uid_t fuid; gid_t fgid; // status fs (used for file access only) + int + tpgid, // stat terminal process group id + exit_signal, // stat might not be SIGCHLD + processor; // stat current (or most recent?) CPU + int + oom_score, // oom_score (badness for OOM killer) + oom_adj; // oom_adj (adjustment to OOM score) + struct procps_ns ns; // (ns subdir) inode number of namespaces + char + *sd_mach, // n/a systemd vm/container name + *sd_ouid, // n/a systemd session owner uid + *sd_seat, // n/a systemd login session seat + *sd_sess, // n/a systemd login session id + *sd_slice, // n/a systemd slice unit + *sd_unit, // n/a systemd system unit id + *sd_uunit; // n/a systemd user unit id + char + *lxcname, // n/a lxc container name + *exe; // exe executable path + name + int + luid, // loginuid user id at login + autogrp_id, // autogroup autogroup number (id) + autogrp_nice; // autogroup autogroup nice value + + bool valid; + + void Log(void) const; + void Update(void); + bool Kill(void) const; + void FreeFileData(char * buf) const; + char * GetFileData(const char * fmt, pid_t _ppid, pid_t _tpid, ssize_t *readed) const; + explicit Process(pid_t pid, CPUTimes & ct); + explicit Process(pid_t pid); + ~Process(); +protected: +}; + +#endif // __PROCESS_H__ \ No newline at end of file diff --git a/src/process/processes.cpp b/src/process/processes.cpp new file mode 100644 index 0000000..0481255 --- /dev/null +++ b/src/process/processes.cpp @@ -0,0 +1,111 @@ +#include "processes.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#ifndef MAIN_PROCESSES +extern const char * LOG_FILE; +#else +const char * LOG_FILE = ""; +#endif + +#define LOG_SOURCE_FILE "processes.cpp" + +#if INTPTR_MAX == INT32_MAX +#define LLFMT "%llu" +#elif INTPTR_MAX == INT64_MAX +#define LLFMT "%lu" +#else + #error "Environment not 32 or 64-bit." +#endif + +Processes::Processes() +{ + LOG_INFO("\n"); + memset(&ct, 0, sizeof(ct)); + Update(); +}; + +bool Processes::Update(void) +{ + LOG_INFO("\n"); + + GetCPUTimes(&ct); + + auto proc = opendir("/proc"); + if( !proc ) { + LOG_ERROR("opendir(\"/proc\") ... error (%s)\n", errorname(errno)); + return false; + } + + total_percent = 0.0F; + + struct dirent * entry; + std::set valid_pid; + while( (entry = readdir(proc)) ) { + if( entry->d_type != DT_DIR ) + continue; + pid_t pid; + if( !(pid = strtoul(entry->d_name, NULL, 10)) ) + continue; + + valid_pid.insert(pid); + + if( procs.find(pid) == procs.end() ) + procs[pid] = std::make_unique(pid, ct); + else + procs[pid]->Update(); + + total_percent += procs[pid]->percent_cpu; + } + closedir(proc); + + std::set invalid_pid; + + for( const auto& [id, ps] : procs ) + if( valid_pid.find(id) == valid_pid.end() ) + invalid_pid.insert(id); + + for( const auto _pid : invalid_pid ) { + LOG_INFO("delete process %u\n", _pid); + procs.extract( _pid ); + } + + LOG_INFO("total_percent %f%%\n", total_percent); + + return true; +} + +Processes::~Processes() +{ + LOG_INFO("\n"); +}; + + +void Processes::Log(void) +{ + +} + +#ifdef MAIN_PROCESSES +int main(int argc, char * argv[]) +{ + Processes procs = Processes(); + procs.Update(); + procs.Log(); + LOG_INFO("============================================================\n"); + sleep(3); + procs.Update(); + LOG_INFO("============================================================\n"); + sleep(3); + procs.Update(); + return 0; +} +#endif //MAIN_PROCESSES diff --git a/src/process/processes.h b/src/process/processes.h new file mode 100644 index 0000000..e20bdf0 --- /dev/null +++ b/src/process/processes.h @@ -0,0 +1,27 @@ +#ifndef __PROCESSES_H__ +#define __PROCESSES_H__ + +#include "process.h" +#include +#include + +struct Processes { + std::map> procs; + + typedef std::map>::const_iterator const_iterator; + const_iterator begin() const { return procs.begin(); }; + const_iterator end() const { return procs.end(); }; + const_iterator find(pid_t pid) const { return procs.find(pid); }; + int size(void) const { return procs.size(); }; + + CPUTimes ct; + + float total_percent; + + bool Update(void); + void Log(void); + Processes(); + ~Processes(); +}; + +#endif // __PROCESSES_H__ \ No newline at end of file diff --git a/src/procpanel.cpp b/src/procpanel.cpp new file mode 100644 index 0000000..cf85b13 --- /dev/null +++ b/src/procpanel.cpp @@ -0,0 +1,143 @@ +#include "procpanel.h" +#include "fardialog.h" +#include "progress.h" +#include +#include +#include + +extern const char * LOG_FILE; +#define LOG_SOURCE_FILE "procpanel.cpp" + +ProcPanel::ProcPanel(PanelIndex index_, std::unique_ptr & processes_): + FarPanel(index_), + processes(processes_) +{ + LOG_INFO("\n"); +} + +ProcPanel::~ProcPanel() +{ + LOG_INFO("\n"); +} + +int ProcPanel::ProcessKey(HANDLE hPlugin, int key, unsigned int controlState, bool & change) +{ + LOG_INFO("\n"); + if( controlState == PKF_CONTROL && key == VK_F4) { + LOG_INFO("PKF_CONTROL+VK_F4\n"); + change = true; + Plugin::psi.Control(this, FCTL_SETSORTMODE, SM_NUMLINKS, 0); + return TRUE; + } + + return IsPanelProcessKey(key, controlState); +} + +int ProcPanel::GetFindData(struct PluginPanelItem **pPanelItem, int *pItemsNumber) +{ + LOG_INFO("\n"); + + *pItemsNumber = processes->procs.size(); + *pPanelItem = (struct PluginPanelItem *)malloc((*pItemsNumber) * sizeof(PluginPanelItem)); + memset(*pPanelItem, 0, (*pItemsNumber) * sizeof(PluginPanelItem)); + PluginPanelItem * pi = *pPanelItem; + + for( const auto & [pid, proc]: processes->procs ) { + pi->FindData.lpwszFileName = wcsdup(MB2Wide(proc->name.c_str()).c_str()); + pi->FindData.dwFileAttributes |= FILE_FLAG_DELETE_ON_CLOSE; + + if( proc->flags & PF_KTHREAD ) + pi->FindData.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN; + + pi->FindData.nFileSize = ((uint64_t)proc->m_resident)*proc->pageSize; + pi->NumberOfLinks = (DWORD)(proc->percent_cpu * 100.0); + + const wchar_t ** customColumnData = (const wchar_t **)malloc(ProcColumnMaxIndex*sizeof(const wchar_t *)); + if( customColumnData ) { + memset(customColumnData, 0, ProcColumnMaxIndex*sizeof(const wchar_t *)); + customColumnData[ProcColumnPidIndex] = DublicateCountString(proc->pid); + customColumnData[ProcColumnPriorityIndex] = DublicateCountString(proc->priority); + customColumnData[ProcColumnNiceIndex] = DublicateCountString(proc->nice); + customColumnData[ProcColumnCpuIndex] = DublicateFloatPercentString(proc->percent_cpu); + pi->CustomColumnNumber = ProcColumnMaxIndex; + pi->CustomColumnData = customColumnData; + } + pi++; + } + return int(true); +} + +void ProcPanel::FreeFindData(struct PluginPanelItem * panelItem, int itemsNumber_) +{ + LOG_INFO("\n"); + auto itemsNumber = itemsNumber_; + while( itemsNumber-- ) { + assert( (panelItem+itemsNumber)->FindData.dwFileAttributes & FILE_FLAG_DELETE_ON_CLOSE ); + free((void *)(panelItem+itemsNumber)->FindData.lpwszFileName); + } + FarPanel::FreeFindData(panelItem, itemsNumber_); +} + +int ProcPanel::ProcessEvent(int event, void *param) +{ + LOG_INFO("\n"); + if( event != FE_IDLE ) + return int(false); + + processes->Update(); + + Plugin::psi.Control(this, FCTL_UPDATEPANEL, TRUE, 0); + Plugin::psi.Control(this, FCTL_REDRAWPANEL, 0, 0); + + return int(true); +} + +void ProcPanel::GetOpenPluginInfo(struct OpenPluginInfo * info) +{ + FarPanel::GetOpenPluginInfo(info); + static wchar_t panelName[sizeof("Process list: 100000.00% ")]; + if( Plugin::FSF.snprintf(panelName, ARRAYSIZE(panelName), L"%S CPU(%.02f%%)", GetMsg(MPanelProcessTitle), processes->total_percent) > 0 ) + info->PanelTitle = panelName; +} + +int ProcPanel::DeleteFiles(struct PluginPanelItem *panelItem, int itemsNumber, int opMode) +{ + LOG_INFO("\n"); + if( itemsNumber == 1 && panelItem->FindData.lpwszFileName && Plugin::FSF.LStricmp(panelItem->FindData.lpwszFileName, L"..") == 0 ) + return int(false); + + + PluginPanelItem * pi = panelItem; + auto _itemsNumber = itemsNumber; + + std::vector items; + std::vector msg; + items.push_back(L"Kill processes: "); + msg.push_back(items.back().c_str()); + + while( _itemsNumber-- ) { + std::wstring m; + m += L"["; + m += pi->CustomColumnData[ProcColumnPidIndex]; + m += L"] "; + m += pi->FindData.lpwszFileName; + items.push_back(m); + msg.push_back(items.back().c_str()); + pi++; + } + + if( Plugin::psi.Message(Plugin::psi.ModuleNumber, FMSG_MB_YESNO | FMSG_WARNING, nullptr, &msg.front(), msg.size(), 0) != 0) + return int(false); + + pi = panelItem; + while( itemsNumber-- ) { + Process proc(Plugin::FSF.atoi(pi->CustomColumnData[ProcColumnPidIndex])); + proc.Kill(); + pi++; + } + + Plugin::psi.Control(this, FCTL_UPDATEPANEL, TRUE, 0); + Plugin::psi.Control(this, FCTL_REDRAWPANEL, 0, 0); + + return int(true); +} diff --git a/src/procpanel.h b/src/procpanel.h new file mode 100644 index 0000000..4e6cc30 --- /dev/null +++ b/src/procpanel.h @@ -0,0 +1,37 @@ +#ifndef __PROCPANEL_H__ +#define __PROCPANEL_H__ + +#include "farpanel.h" +#include "process/processes.h" + +enum { + ProcColumnPidIndex, + ProcColumnPriorityIndex, + ProcColumnNiceIndex, + ProcColumnCpuIndex, + ProcColumnMaxIndex +}; + +class ProcPanel : public FarPanel +{ +private: + + std::unique_ptr & processes; + + // copy and assignment not allowed + ProcPanel(const ProcPanel&) = delete; + void operator=(const ProcPanel&) = delete; + +public: + int ProcessKey(HANDLE hPlugin, int key, unsigned int controlState, bool & change) override; + int GetFindData(struct PluginPanelItem **pPanelItem, int *pItemsNumber) override; + void FreeFindData(struct PluginPanelItem * panelItem, int itemsNumber) override; + int ProcessEvent(int event, void *param) override; + void GetOpenPluginInfo(struct OpenPluginInfo * info) override; + int DeleteFiles(struct PluginPanelItem *panelItem, int itemsNumber, int opMode) override; + explicit ProcPanel(PanelIndex index, std::unique_ptr & processes); + virtual ~ProcPanel(); +}; + + +#endif // __PROCPANEL__ diff --git a/src/procplugin.cpp b/src/procplugin.cpp new file mode 100644 index 0000000..d767db4 --- /dev/null +++ b/src/procplugin.cpp @@ -0,0 +1,56 @@ +#include "procplugin.h" +#include "procpanel.h" + +#include + +#include + +#include + +extern const char * LOG_FILE; +#define LOG_SOURCE_FILE "procplugin.cpp" + +ProcPlugin::ProcPlugin(const PluginStartupInfo * info): + Plugin(info) +{ + LOG_INFO("\n"); + processes = std::make_unique(); +} + +ProcPlugin::~ProcPlugin() +{ + LOG_INFO("\n"); +} + +HANDLE ProcPlugin::OpenFilePlugin(const wchar_t * name,const unsigned char * data, int dataSize, int opMode) +{ + return INVALID_HANDLE_VALUE; +} + +HANDLE ProcPlugin::OpenPlugin(int openFrom, INT_PTR item) +{ + if( openFrom == OPEN_DISKMENU || openFrom == OPEN_PLUGINSMENU ) { + auto process = std::make_unique(ProcessPanelIndex, processes); + if( process->Valid() ) { + panel.push_back(std::move(process)); + return panel.back().get(); + } + } + return INVALID_HANDLE_VALUE; +} + +void ProcPlugin::ClosePlugin(HANDLE hPlugin) +{ + LOG_INFO("hPlugin %p\n", hPlugin); + for( auto it = panel.begin(); it != panel.end(); it++ ) + if( (*it).get() == hPlugin ) { + panel.erase(it); + break; + } +} + +int ProcPlugin::GetFindData(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber) +{ + LOG_INFO("\n"); + return static_cast(hPlugin)->GetFindData(pPanelItem, pItemsNumber); +} diff --git a/src/procplugin.h b/src/procplugin.h new file mode 100644 index 0000000..8226bfd --- /dev/null +++ b/src/procplugin.h @@ -0,0 +1,41 @@ +#ifndef __PROCPLUGIN_H__ +#define __PROCPLUGIN_H__ + +#include "plugin.h" +#include "process/processes.h" + +struct PluginUserData { + DWORD size; + union { + void * data; + Process * proc; + } data; +}; + +class ProcPlugin : public Plugin { + private: + // Panels + enum { + PanelProcesses, + PanelTypeMax + }; + + std::unique_ptr processes; + + // copy and assignment not allowed + ProcPlugin(const ProcPlugin&) = delete; + void operator=(const ProcPlugin&) = delete; + + public: + + explicit ProcPlugin(const PluginStartupInfo * info); + virtual ~ProcPlugin() override; + + // far2l api + HANDLE OpenFilePlugin(const wchar_t * name,const unsigned char * data, int dataSize, int opMode) override; + int GetFindData(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber) override; + HANDLE OpenPlugin(int openFrom, INT_PTR item) override; + void ClosePlugin(HANDLE hPlugin) override; +}; + +#endif /* __PROCPLUGIN_H__ */ diff --git a/src/progress.cpp b/src/progress.cpp new file mode 100644 index 0000000..57ff16d --- /dev/null +++ b/src/progress.cpp @@ -0,0 +1,107 @@ +/************************************************************************** + * SQLiteDB plug-in for FAR 3.0 modifed by VPROFi 2023 for far2l * + * Copyright (C) 2010-2014 by Artem Senichev * + * https://sourceforge.net/projects/farplugs/ * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + **************************************************************************/ + +#include "progress.h" +#include "lng.h" +#include + +#define PROGRESS_WIDTH 30 + +progress::progress(const int msg_id, const uint64_t max_value /*= 0*/) +: _visible(false), + _max_value(max_value) +{ + _title = Plugin::psi.GetMsg(Plugin::psi.ModuleNumber, ps_title_short); + _message = Plugin::psi.GetMsg(Plugin::psi.ModuleNumber, msg_id); + show(); +} + + +progress::~progress() +{ + hide(); +} + + +void progress::show() +{ + if (!_visible) { + _visible = true; + Plugin::psi.AdvControl(Plugin::psi.ModuleNumber, ACTL_SETPROGRESSSTATE, (void*)PGS_INDETERMINATE); + } + + if (_bar.empty()) { + const wchar_t* msg[] = { _title, _message }; + Plugin::psi.Message(Plugin::psi.ModuleNumber, 0, nullptr, msg, sizeof(msg) / sizeof(msg[0]), 0); + } + else { + const wchar_t* msg[] = { _title, _message, _bar.c_str() }; + Plugin::psi.Message(Plugin::psi.ModuleNumber, 0, nullptr, msg, sizeof(msg) / sizeof(msg[0]), 0); + } +} + + +void progress::hide() +{ + if (_visible) { + Plugin::psi.AdvControl(Plugin::psi.ModuleNumber, ACTL_PROGRESSNOTIFY, 0); + Plugin::psi.AdvControl(Plugin::psi.ModuleNumber, ACTL_SETPROGRESSSTATE, (void*)PGS_NOPROGRESS); + Plugin::psi.Control(PANEL_ACTIVE, FCTL_REDRAWPANEL, 0, 0); + Plugin::psi.Control(PANEL_PASSIVE, FCTL_REDRAWPANEL, 0, 0); + _visible = false; + } +} + + +void progress::update(const uint64_t val) +{ + if (!_max_value) + return; + + const size_t percent = static_cast((val * 100) / _max_value); + assert(percent <= 100); + + PROGRESSVALUE pv; + memset(&pv, 0, sizeof(pv)); + pv.Completed = percent; + pv.Total = 100; + Plugin::psi.AdvControl(Plugin::psi.ModuleNumber, ACTL_SETPROGRESSVALUE, &pv); + + if (_bar.empty()) + _bar.resize(PROGRESS_WIDTH); + const size_t fill_length = percent * _bar.size() / 100; + std::fill(_bar.begin() + fill_length, _bar.end(), L'\x2591'); + std::fill(_bar.begin(), _bar.begin() + fill_length, L'\x2588'); + + show(); +} + + +bool progress::aborted() +{ + HANDLE std_in = stdin; + INPUT_RECORD rec; + DWORD read_count = 0; + while( PeekConsoleInput(std_in, &rec, 1, &read_count) && read_count != 0 ) { + ReadConsoleInput(std_in, &rec, 1, &read_count); + if( rec.EventType == KEY_EVENT && rec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE && rec.Event.KeyEvent.bKeyDown ) + return true; + } + return false; +} diff --git a/src/progress.h b/src/progress.h new file mode 100644 index 0000000..ae90c06 --- /dev/null +++ b/src/progress.h @@ -0,0 +1,68 @@ +#ifndef __PROGRESS_H__ +#define __PROGRESS_H__ + +/************************************************************************** + * SQLiteDB plug-in for FAR 3.0 modifed by VPROFi 2023 for far2l * + * Copyright (C) 2010-2014 by Artem Senichev * + * https://sourceforge.net/projects/farplugs/ * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + **************************************************************************/ + +#include "plugin.h" +#include + +class progress +{ +public: + /** + * Constructor. + * \param msg_id window message id + * \param max_value maximal progress value (0 to disable progress) + */ + progress(const int msg_id, const uint64_t max_value = 0); + + ~progress(); + + /** + * Show progress window. + */ + void show(); + + /** + * Hide progress window. + */ + void hide(); + + /** + * Set progress value. + * \param val new progress value + */ + void update(const uint64_t val); + + /** + * Check for abort request. + * \return true if user requested abort + */ + static bool aborted(); + +private: + bool _visible; ///< Visible flag + const wchar_t* _title; ///< Window title + const wchar_t* _message; ///< Window message + uint64_t _max_value; ///< Maximum progress value + std::wstring _bar; ///< Progress bar +}; + +#endif //__PROGRESS_H__ \ No newline at end of file diff --git a/vendor/far2l b/vendor/far2l new file mode 160000 index 0000000..e0f8fd0 --- /dev/null +++ b/vendor/far2l @@ -0,0 +1 @@ +Subproject commit e0f8fd044ebd9657c87a7ac858fdf7799451e7ce