creat shutdown.h i system_utils.h
fix: arreglants uns includes per a windows
This commit is contained in:
@@ -81,7 +81,9 @@ set(APP_SOURCES
|
||||
source/input_types.cpp
|
||||
source/mouse.cpp
|
||||
source/options.cpp
|
||||
source/shutdown.cpp
|
||||
source/stage.cpp
|
||||
source/system_utils.cpp
|
||||
source/utils.cpp
|
||||
)
|
||||
|
||||
|
||||
68
Makefile
68
Makefile
@@ -22,37 +22,42 @@ RASPI_RELEASE := $(TARGET_FILE)-$(VERSION)-raspberry.tar.gz
|
||||
|
||||
# Lista completa de archivos fuente (basada en CMakeLists.txt)
|
||||
APP_SOURCES := \
|
||||
source/animated_sprite.cpp \
|
||||
source/asset.cpp \
|
||||
source/audio.cpp \
|
||||
source/director.cpp \
|
||||
source/global_events.cpp \
|
||||
source/global_inputs.cpp \
|
||||
source/input.cpp \
|
||||
source/lang.cpp \
|
||||
source/main.cpp \
|
||||
source/param.cpp \
|
||||
source/resource.cpp \
|
||||
source/screen.cpp \
|
||||
source/text.cpp \
|
||||
source/writer.cpp \
|
||||
source/ui/menu_option.cpp \
|
||||
source/ui/menu_renderer.cpp \
|
||||
source/ui/notifier.cpp \
|
||||
source/ui/service_menu.cpp \
|
||||
source/ui/ui_message.cpp \
|
||||
source/ui/window_message.cpp \
|
||||
source/background.cpp \
|
||||
source/balloon_formations.cpp \
|
||||
source/balloon_manager.cpp \
|
||||
source/balloon.cpp \
|
||||
source/bullet.cpp \
|
||||
source/color.cpp \
|
||||
source/define_buttons.cpp \
|
||||
source/difficulty.cpp \
|
||||
source/director.cpp \
|
||||
source/enter_name.cpp \
|
||||
source/explosions.cpp \
|
||||
source/external/gif.cpp \
|
||||
source/external/jail_audio.cpp \
|
||||
source/external/jail_shader.cpp \
|
||||
source/fade.cpp \
|
||||
source/game_logo.cpp \
|
||||
source/global_events.cpp \
|
||||
source/global_inputs.cpp \
|
||||
source/input_types.cpp \
|
||||
source/input.cpp \
|
||||
source/item.cpp \
|
||||
source/lang.cpp \
|
||||
source/main.cpp \
|
||||
source/manage_hiscore_table.cpp \
|
||||
source/mouse.cpp \
|
||||
source/moving_sprite.cpp \
|
||||
source/options.cpp \
|
||||
source/param.cpp \
|
||||
source/path_sprite.cpp \
|
||||
source/player.cpp \
|
||||
source/resource.cpp \
|
||||
source/scoreboard.cpp \
|
||||
source/tabe.cpp \
|
||||
source/screen.cpp \
|
||||
source/sections/credits.cpp \
|
||||
source/sections/game.cpp \
|
||||
source/sections/hiscore_table.cpp \
|
||||
@@ -60,26 +65,23 @@ APP_SOURCES := \
|
||||
source/sections/intro.cpp \
|
||||
source/sections/logo.cpp \
|
||||
source/sections/title.cpp \
|
||||
source/animated_sprite.cpp \
|
||||
source/background.cpp \
|
||||
source/fade.cpp \
|
||||
source/moving_sprite.cpp \
|
||||
source/path_sprite.cpp \
|
||||
source/shutdown.cpp \
|
||||
source/smart_sprite.cpp \
|
||||
source/sprite.cpp \
|
||||
source/stage.cpp \
|
||||
source/system_utils.cpp \
|
||||
source/tabe.cpp \
|
||||
source/text.cpp \
|
||||
source/texture.cpp \
|
||||
source/tiled_bg.cpp \
|
||||
source/color.cpp \
|
||||
source/define_buttons.cpp \
|
||||
source/difficulty.cpp \
|
||||
source/input_types.cpp \
|
||||
source/mouse.cpp \
|
||||
source/options.cpp \
|
||||
source/stage.cpp \
|
||||
source/ui/menu_option.cpp \
|
||||
source/ui/menu_renderer.cpp \
|
||||
source/ui/notifier.cpp \
|
||||
source/ui/service_menu.cpp \
|
||||
source/ui/ui_message.cpp \
|
||||
source/ui/window_message.cpp \
|
||||
source/utils.cpp \
|
||||
source/external/jail_shader.cpp \
|
||||
source/external/jail_audio.cpp \
|
||||
source/external/gif.cpp
|
||||
source/writer.cpp
|
||||
|
||||
# Includes
|
||||
INCLUDES := -Isource -Isource/external
|
||||
|
||||
@@ -8,9 +8,8 @@ fi
|
||||
|
||||
FILE="$1"
|
||||
|
||||
include-what-you-use -D DEBUG -D VERBOSE -std=c++20 -Wall "$FILE" \
|
||||
include-what-you-use -D _DEBUG -std=c++20 -Wall "$FILE" \
|
||||
-I../source \
|
||||
-Xiwyu --mapping_file=sdl3_mapping.imp \
|
||||
-Xiwyu --update_comments \
|
||||
-Xiwyu --verbose=3 \
|
||||
| \
|
||||
python3 /usr/bin/fix_includes.py --update_comments
|
||||
-Xiwyu --verbose=3
|
||||
@@ -1,22 +1,17 @@
|
||||
// IWYU pragma: no_include <bits/chrono.h>
|
||||
#include "director.h"
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_LogCategory, SDL_LogInfo, SDL_SetLogPriority, SDL_LogPriority, SDL_Quit
|
||||
#include <sys/stat.h> // Para mkdir, stat, S_IRWXU
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h> // Para getuid
|
||||
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_SetLogPriority, SDL_LogPriority, SDL_Quit
|
||||
|
||||
#include <cerrno> // Para errno, EEXIST, EACCES, ENAMETOOLONG
|
||||
#include <cstdio> // Para printf, perror
|
||||
#include <cstdlib> // Para exit, EXIT_FAILURE, srand, rand, system
|
||||
#include <cstdlib> // Para srand, exit, rand, EXIT_FAILURE
|
||||
#include <ctime> // Para time
|
||||
#include <iostream> // Para std::cerr
|
||||
#include <iostream> // Para basic_ostream, operator<<, cerr, endl
|
||||
#include <memory> // Para make_unique, unique_ptr
|
||||
#include <span> // Para span
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <string> // Para operator+, allocator, char_traits, operator==, string, basic_string
|
||||
#include <string> // Para allocator, char_traits, operator==, string, basic_string, operator+
|
||||
|
||||
#include "asset.h" // Para Asset, AssetType
|
||||
#include "asset.h" // Para Asset
|
||||
#include "audio.h" // Para Audio
|
||||
#include "input.h" // Para Input
|
||||
#include "lang.h" // Para setLanguage
|
||||
@@ -34,19 +29,12 @@
|
||||
#include "sections/intro.h" // Para Intro
|
||||
#include "sections/logo.h" // Para Logo
|
||||
#include "sections/title.h" // Para Title
|
||||
#include "shutdown.h" // Para resultToString, shutdownSystem, ShutdownResult
|
||||
#include "system_utils.h" // Para createApplicationFolder, resultToString, Result
|
||||
#include "ui/notifier.h" // Para Notifier
|
||||
#include "ui/service_menu.h" // Para ServiceMenu
|
||||
#include "utils.h" // Para Overrides, overrides, getPath
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pwd.h> // Para getpwuid, passwd
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winbase.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// Constructor
|
||||
Director::Director(int argc, std::span<char *> argv) {
|
||||
#ifdef RECORDING
|
||||
@@ -90,11 +78,7 @@ void Director::init() {
|
||||
// Configuración inicial de parametros
|
||||
Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos
|
||||
loadAssets(); // Crea el índice de archivos
|
||||
|
||||
Input::init(
|
||||
Asset::get()->get("gamecontrollerdb.txt"),
|
||||
Asset::get()->get("controllers.json")); // Carga configuración de controles
|
||||
|
||||
Input::init(Asset::get()->get("gamecontrollerdb.txt"), Asset::get()->get("controllers.json")); // Carga configuración de controles
|
||||
Options::setConfigFile(Asset::get()->get("config.txt")); // Establece el fichero de configuración
|
||||
Options::setControllersFile(Asset::get()->get("controllers.json")); // Establece el fichero de configuración de mandos
|
||||
Options::loadFromFile(); // Carga el archivo de configuración
|
||||
@@ -200,57 +184,13 @@ void Director::checkProgramArguments(int argc, std::span<char *> argv) {
|
||||
|
||||
// Crea la carpeta del sistema donde guardar datos
|
||||
void Director::createSystemFolder(const std::string &folder) {
|
||||
#ifdef _WIN32
|
||||
system_folder_ = std::string(getenv("APPDATA")) + "/" + folder;
|
||||
#elif __APPLE__
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
system_folder_ = std::string(homedir) + "/Library/Application Support" + "/" + folder;
|
||||
#elif __linux__
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
system_folder_ = std::string(homedir) + "/.config/" + folder;
|
||||
auto result = SystemUtils::createApplicationFolder(folder, system_folder_);
|
||||
|
||||
{
|
||||
// Intenta crear ".config", per si no existeix
|
||||
std::string config_base_folder = std::string(homedir) + "/.config";
|
||||
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
|
||||
if (ret == -1 && errno != EEXIST) {
|
||||
printf("ERROR CREATING CONFIG BASE FOLDER.");
|
||||
if (result != SystemUtils::Result::SUCCESS) {
|
||||
std::cerr << "Error creando carpeta del sistema: "
|
||||
<< SystemUtils::resultToString(result) << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct stat st = {0};
|
||||
if (stat(system_folder_.c_str(), &st) == -1) {
|
||||
errno = 0;
|
||||
#ifdef _WIN32
|
||||
int ret = mkdir(system_folder_.c_str());
|
||||
#else
|
||||
int ret = mkdir(system_folder_.c_str(), S_IRWXU);
|
||||
#endif
|
||||
|
||||
if (ret == -1) {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
printf("the parent directory does not allow write");
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
case EEXIST:
|
||||
printf("pathname already exists");
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
case ENAMETOOLONG:
|
||||
printf("pathname is too long");
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
default:
|
||||
perror("mkdir");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ejecuta la sección con el logo
|
||||
@@ -377,75 +317,11 @@ auto Director::run() -> int {
|
||||
|
||||
// Apaga el sistema de forma segura
|
||||
void Director::shutdownSystem(bool should_shutdown) {
|
||||
if (!should_shutdown) {
|
||||
return;
|
||||
}
|
||||
if (should_shutdown) {
|
||||
auto result = SystemShutdown::shutdownSystem(5, true); // 5 segundos, forzar apps
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows: Usar API nativa de Windows
|
||||
if (!InitiateSystemShutdownA(
|
||||
NULL, // lpMachineName (NULL = local machine)
|
||||
"Sistema apagándose...", // lpMessage
|
||||
5, // dwTimeout (5 segundos)
|
||||
TRUE, // bForceAppsClosed
|
||||
FALSE // bRebootAfterShutdown (FALSE = shutdown)
|
||||
)) {
|
||||
std::cerr << "Error: No se pudo iniciar el apagado en Windows. Código: "
|
||||
<< GetLastError() << std::endl;
|
||||
if (result != SystemShutdown::ShutdownResult::SUCCESS) {
|
||||
std::cerr << SystemShutdown::resultToString(result) << std::endl;
|
||||
}
|
||||
|
||||
#elif __APPLE__
|
||||
// macOS: Usar execvp con fork
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
// Proceso hijo - ejecutar shutdown
|
||||
char *args[] = {
|
||||
const_cast<char *>("shutdown"),
|
||||
const_cast<char *>("-h"),
|
||||
const_cast<char *>("+0.1"),
|
||||
NULL};
|
||||
execvp("shutdown", args);
|
||||
// Si execvp falla, salir del proceso hijo
|
||||
std::cerr << "Error: execvp falló en macOS" << std::endl;
|
||||
_exit(1);
|
||||
} else if (pid > 0) {
|
||||
// Proceso padre - esperar al hijo
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
std::cerr << "Error: Comando shutdown falló en macOS" << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Error: No se pudo crear proceso fork en macOS" << std::endl;
|
||||
}
|
||||
|
||||
#elif __linux__
|
||||
// Linux: Usar execvp con fork
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
// Proceso hijo - primero sleep, luego shutdown
|
||||
sleep(5);
|
||||
char *args[] = {
|
||||
const_cast<char *>("shutdown"),
|
||||
const_cast<char *>("-h"),
|
||||
const_cast<char *>("now"),
|
||||
NULL};
|
||||
execvp("shutdown", args);
|
||||
// Si execvp falla, salir del proceso hijo
|
||||
std::cerr << "Error: execvp falló en Linux" << std::endl;
|
||||
_exit(1);
|
||||
} else if (pid > 0) {
|
||||
// Proceso padre - esperar al hijo
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
std::cerr << "Error: Comando shutdown falló en Linux" << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Error: No se pudo crear proceso fork en Linux" << std::endl;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Sistema operativo no soportado"
|
||||
#endif
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <string> // Para manejar cadenas de texto
|
||||
#include <span> // Para Span
|
||||
#include <string> // Para string
|
||||
|
||||
namespace Lang {
|
||||
enum class Code : int;
|
||||
|
||||
165
source/shutdown.cpp
Normal file
165
source/shutdown.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#include "shutdown.h"
|
||||
#include <iostream>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
namespace SystemShutdown {
|
||||
|
||||
#ifndef _WIN32
|
||||
// Función auxiliar para sistemas Unix-like
|
||||
ShutdownResult executeUnixShutdown(const char* command, char* const args[]) {
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0) {
|
||||
// Proceso hijo
|
||||
execvp(command, args);
|
||||
// Si llegamos aquí, execvp falló
|
||||
std::cerr << "Error: No se pudo ejecutar " << command << std::endl;
|
||||
_exit(1);
|
||||
} else if (pid > 0) {
|
||||
// Proceso padre
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
return (WEXITSTATUS(status) == 0) ? ShutdownResult::SUCCESS : ShutdownResult::ERROR_SYSTEM_CALL;
|
||||
} else {
|
||||
return ShutdownResult::ERROR_FORK_FAILED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Implementación de las funciones públicas
|
||||
ShutdownResult shutdownSystem() {
|
||||
ShutdownConfig config;
|
||||
return shutdownSystem(config);
|
||||
}
|
||||
|
||||
ShutdownResult shutdownSystem(int delay_seconds, bool force_apps) {
|
||||
ShutdownConfig config;
|
||||
config.delay_seconds = delay_seconds;
|
||||
config.force_close_apps = force_apps;
|
||||
return shutdownSystem(config);
|
||||
}
|
||||
|
||||
ShutdownResult shutdownSystem(const ShutdownConfig& config) {
|
||||
#ifdef _WIN32
|
||||
// Windows: Usar CreateProcess
|
||||
STARTUPINFOA si = {0};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
si.cb = sizeof(si);
|
||||
|
||||
// Crear comando con el delay especificado
|
||||
std::string command = "shutdown.exe /s /t " + std::to_string(config.delay_seconds);
|
||||
if (config.force_close_apps) {
|
||||
command += " /f";
|
||||
}
|
||||
|
||||
// CreateProcess necesita un array de char modificable
|
||||
char* cmd_buffer = new char[command.length() + 1];
|
||||
strcpy(cmd_buffer, command.c_str());
|
||||
|
||||
bool success = CreateProcessA(
|
||||
NULL, // lpApplicationName
|
||||
cmd_buffer, // lpCommandLine
|
||||
NULL, // lpProcessAttributes
|
||||
NULL, // lpThreadAttributes
|
||||
FALSE, // bInheritHandles
|
||||
0, // dwCreationFlags
|
||||
NULL, // lpEnvironment
|
||||
NULL, // lpCurrentDirectory
|
||||
&si, // lpStartupInfo
|
||||
&pi // lpProcessInformation
|
||||
);
|
||||
|
||||
delete[] cmd_buffer;
|
||||
|
||||
if (success) {
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
return ShutdownResult::SUCCESS;
|
||||
} else {
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_ACCESS_DENIED) {
|
||||
return ShutdownResult::ERROR_PERMISSION;
|
||||
}
|
||||
return ShutdownResult::ERROR_SYSTEM_CALL;
|
||||
}
|
||||
|
||||
#elif __APPLE__
|
||||
// macOS
|
||||
std::string delay_str = "+" + std::to_string(config.delay_seconds / 60.0, 1); // convertir a minutos
|
||||
if (config.delay_seconds < 60) {
|
||||
delay_str = "+0.1"; // mínimo delay en macOS
|
||||
}
|
||||
|
||||
char* args[] = {
|
||||
const_cast<char*>("shutdown"),
|
||||
const_cast<char*>("-h"),
|
||||
const_cast<char*>(delay_str.c_str()),
|
||||
NULL
|
||||
};
|
||||
|
||||
return executeUnixShutdown("shutdown", args);
|
||||
|
||||
#elif __linux__
|
||||
// Linux
|
||||
std::string delay_str = "+" + std::to_string((config.delay_seconds + 59) / 60); // redondear hacia arriba a minutos
|
||||
if (config.delay_seconds == 0) {
|
||||
delay_str = "now";
|
||||
}
|
||||
|
||||
char* args[] = {
|
||||
const_cast<char*>("shutdown"),
|
||||
const_cast<char*>("-h"),
|
||||
const_cast<char*>(delay_str.c_str()),
|
||||
NULL
|
||||
};
|
||||
|
||||
return executeUnixShutdown("shutdown", args);
|
||||
|
||||
#else
|
||||
return ShutdownResult::ERROR_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* resultToString(ShutdownResult result) {
|
||||
switch (result) {
|
||||
case ShutdownResult::SUCCESS:
|
||||
return "Apagado iniciado exitosamente";
|
||||
case ShutdownResult::ERROR_PERMISSION:
|
||||
return "Error: Permisos insuficientes";
|
||||
case ShutdownResult::ERROR_SYSTEM_CALL:
|
||||
return "Error: Fallo en la llamada al sistema";
|
||||
case ShutdownResult::ERROR_FORK_FAILED:
|
||||
return "Error: No se pudo crear proceso hijo";
|
||||
case ShutdownResult::ERROR_UNSUPPORTED:
|
||||
return "Error: Sistema operativo no soportado";
|
||||
default:
|
||||
return "Error desconocido";
|
||||
}
|
||||
}
|
||||
|
||||
bool isShutdownSupported() {
|
||||
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* getRequiredPermissions() {
|
||||
#ifdef _WIN32
|
||||
return "Requiere permisos de Administrador en Windows";
|
||||
#elif defined(__APPLE__) || defined(__linux__)
|
||||
return "Requiere permisos de root/sudo en Unix";
|
||||
#else
|
||||
return "Sistema no soportado";
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace SystemShutdown
|
||||
47
source/shutdown.h
Normal file
47
source/shutdown.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
// Utilidad multiplataforma para apagar el sistema de forma segura
|
||||
namespace SystemShutdown {
|
||||
|
||||
// Códigos de resultado para las operaciones de apagado
|
||||
enum class ShutdownResult {
|
||||
SUCCESS = 0,
|
||||
ERROR_PERMISSION, // Error de permisos insuficientes
|
||||
ERROR_SYSTEM_CALL, // Error en la llamada al sistema
|
||||
ERROR_FORK_FAILED, // Error al crear proceso hijo (Unix)
|
||||
ERROR_UNSUPPORTED // Sistema operativo no soportado
|
||||
};
|
||||
|
||||
// Configuración para el apagado del sistema
|
||||
struct ShutdownConfig {
|
||||
int delay_seconds;
|
||||
bool force_close_apps;
|
||||
const char* shutdown_message;
|
||||
|
||||
// Constructor con valores por defecto
|
||||
ShutdownConfig()
|
||||
: delay_seconds(5)
|
||||
, force_close_apps(true)
|
||||
, shutdown_message("El sistema se apagará...")
|
||||
{}
|
||||
};
|
||||
|
||||
// Apaga el sistema con configuración por defecto
|
||||
ShutdownResult shutdownSystem();
|
||||
|
||||
// Apaga el sistema con configuración personalizada
|
||||
ShutdownResult shutdownSystem(const ShutdownConfig& config);
|
||||
|
||||
// Apaga el sistema con parámetros simples
|
||||
ShutdownResult shutdownSystem(int delay_seconds, bool force_apps = true);
|
||||
|
||||
// Convierte un código de resultado a string descriptivo
|
||||
const char* resultToString(ShutdownResult result);
|
||||
|
||||
// Verifica si el sistema actual soporta apagado programático
|
||||
bool isShutdownSupported();
|
||||
|
||||
// Obtiene información sobre los permisos necesarios en la plataforma actual
|
||||
const char* getRequiredPermissions();
|
||||
|
||||
} // namespace SystemShutdown
|
||||
190
source/system_utils.cpp
Normal file
190
source/system_utils.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#include "system_utils.h"
|
||||
#include <iostream>
|
||||
#include <sys/stat.h>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <direct.h>
|
||||
// Evitar conflictos con macros de Windows
|
||||
#ifdef ERROR_ALREADY_EXISTS
|
||||
#undef ERROR_ALREADY_EXISTS
|
||||
#endif
|
||||
#else
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace SystemUtils {
|
||||
|
||||
// Función auxiliar para crear una carpeta individual
|
||||
Result createSingleFolder(const std::string& path, int permissions) {
|
||||
struct stat st = {0};
|
||||
|
||||
// Verificar si ya existe
|
||||
if (stat(path.c_str(), &st) == 0) {
|
||||
return Result::SUCCESS; // Ya existe, no es error por defecto
|
||||
}
|
||||
|
||||
// Intentar crear la carpeta
|
||||
int result;
|
||||
#ifdef _WIN32
|
||||
result = _mkdir(path.c_str());
|
||||
#else
|
||||
result = mkdir(path.c_str(), permissions);
|
||||
#endif
|
||||
|
||||
if (result == -1) {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
return Result::PERMISSION_DENIED;
|
||||
case EEXIST:
|
||||
return Result::ALREADY_EXISTS;
|
||||
case ENAMETOOLONG:
|
||||
return Result::PATH_TOO_LONG;
|
||||
default:
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
// Función auxiliar para crear carpetas padre recursivamente
|
||||
Result createParentFolders(const std::string& path, int permissions) {
|
||||
size_t pos = 0;
|
||||
|
||||
while ((pos = path.find('/', pos + 1)) != std::string::npos) {
|
||||
std::string parent = path.substr(0, pos);
|
||||
if (!parent.empty() && !folderExists(parent)) {
|
||||
Result result = createSingleFolder(parent, permissions);
|
||||
if (result != Result::SUCCESS && result != Result::ALREADY_EXISTS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
Result createApplicationFolder(const std::string& app_name, std::string& out_path) {
|
||||
FolderConfig config;
|
||||
return createApplicationFolder(app_name, out_path, config);
|
||||
}
|
||||
|
||||
Result createApplicationFolder(const std::string& app_name, std::string& out_path, const FolderConfig& config) {
|
||||
out_path = getApplicationDataPath(app_name);
|
||||
return createFolder(out_path, config);
|
||||
}
|
||||
|
||||
Result createFolder(const std::string& path) {
|
||||
FolderConfig config;
|
||||
return createFolder(path, config);
|
||||
}
|
||||
|
||||
Result createFolder(const std::string& path, const FolderConfig& config) {
|
||||
if (path.empty()) {
|
||||
return Result::INVALID_PATH;
|
||||
}
|
||||
|
||||
// Verificar si ya existe y si eso es un error
|
||||
if (folderExists(path) && config.fail_if_exists) {
|
||||
return Result::ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
// Crear carpetas padre si es necesario
|
||||
if (config.create_parents) {
|
||||
Result parent_result = createParentFolders(path, config.permissions);
|
||||
if (parent_result != Result::SUCCESS) {
|
||||
return parent_result;
|
||||
}
|
||||
}
|
||||
|
||||
// Crear la carpeta final
|
||||
return createSingleFolder(path, config.permissions);
|
||||
}
|
||||
|
||||
std::string getApplicationDataPath(const std::string& app_name) {
|
||||
#ifdef _WIN32
|
||||
char* appdata = getenv("APPDATA");
|
||||
if (appdata) {
|
||||
return std::string(appdata) + "/" + app_name;
|
||||
}
|
||||
return "C:/Users/Default/AppData/Roaming/" + app_name;
|
||||
|
||||
#elif __APPLE__
|
||||
std::string home = getHomeDirectory();
|
||||
return home + "/Library/Application Support/" + app_name;
|
||||
|
||||
#elif __linux__
|
||||
std::string home = getHomeDirectory();
|
||||
return home + "/.config/" + app_name;
|
||||
|
||||
#else
|
||||
// Fallback genérico
|
||||
std::string home = getHomeDirectory();
|
||||
return home + "/." + app_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool folderExists(const std::string& path) {
|
||||
struct stat st = {0};
|
||||
return (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode));
|
||||
}
|
||||
|
||||
const char* resultToString(Result result) {
|
||||
switch (result) {
|
||||
case Result::SUCCESS:
|
||||
return "Operación exitosa";
|
||||
case Result::PERMISSION_DENIED:
|
||||
return "Error: Permisos insuficientes";
|
||||
case Result::PATH_TOO_LONG:
|
||||
return "Error: Ruta demasiado larga";
|
||||
case Result::ALREADY_EXISTS:
|
||||
return "Error: La carpeta ya existe";
|
||||
case Result::INVALID_PATH:
|
||||
return "Error: Ruta inválida";
|
||||
case Result::UNKNOWN_ERROR:
|
||||
return "Error desconocido";
|
||||
default:
|
||||
return "Error no identificado";
|
||||
}
|
||||
}
|
||||
|
||||
std::string getHomeDirectory() {
|
||||
#ifdef _WIN32
|
||||
char* userprofile = getenv("USERPROFILE");
|
||||
if (userprofile) {
|
||||
return std::string(userprofile);
|
||||
}
|
||||
return "C:/Users/Default";
|
||||
#else
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
if (pw && pw->pw_dir) {
|
||||
return std::string(pw->pw_dir);
|
||||
}
|
||||
|
||||
// Fallback
|
||||
char* home = getenv("HOME");
|
||||
if (home) {
|
||||
return std::string(home);
|
||||
}
|
||||
return "/tmp";
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string getTempDirectory() {
|
||||
#ifdef _WIN32
|
||||
char* temp = getenv("TEMP");
|
||||
if (temp) {
|
||||
return std::string(temp);
|
||||
}
|
||||
return "C:/Windows/Temp";
|
||||
#else
|
||||
return "/tmp";
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace SystemUtils
|
||||
59
source/system_utils.h
Normal file
59
source/system_utils.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
// Utilidades multiplataforma para operaciones del sistema
|
||||
namespace SystemUtils {
|
||||
|
||||
// Códigos de resultado para operaciones del sistema
|
||||
enum class Result {
|
||||
SUCCESS = 0,
|
||||
PERMISSION_DENIED, // Sin permisos para crear la carpeta
|
||||
PATH_TOO_LONG, // Ruta demasiado larga
|
||||
ALREADY_EXISTS, // Ya existe (solo si se considera error)
|
||||
INVALID_PATH, // Ruta inválida
|
||||
UNKNOWN_ERROR // Error desconocido
|
||||
};
|
||||
|
||||
// Configuración para creación de carpetas
|
||||
struct FolderConfig {
|
||||
bool create_parents; // Crear carpetas padre si no existen
|
||||
bool fail_if_exists; // Fallar si la carpeta ya existe
|
||||
int permissions; // Permisos Unix (ignorado en Windows)
|
||||
|
||||
// Constructor con valores por defecto
|
||||
FolderConfig()
|
||||
: create_parents(true)
|
||||
, fail_if_exists(false)
|
||||
, permissions(0755) // rwxr-xr-x
|
||||
{}
|
||||
};
|
||||
|
||||
// Crea la carpeta del sistema donde guardar datos de la aplicación
|
||||
Result createApplicationFolder(const std::string& app_name, std::string& out_path);
|
||||
|
||||
// Crea la carpeta del sistema con configuración personalizada
|
||||
Result createApplicationFolder(const std::string& app_name, std::string& out_path, const FolderConfig& config);
|
||||
|
||||
// Crea una carpeta en la ruta especificada
|
||||
Result createFolder(const std::string& path);
|
||||
|
||||
// Crea una carpeta con configuración personalizada
|
||||
Result createFolder(const std::string& path, const FolderConfig& config);
|
||||
|
||||
// Obtiene la ruta de datos de la aplicación (sin crearla)
|
||||
std::string getApplicationDataPath(const std::string& app_name);
|
||||
|
||||
// Verifica si una carpeta existe
|
||||
bool folderExists(const std::string& path);
|
||||
|
||||
// Convierte un código de resultado a string descriptivo
|
||||
const char* resultToString(Result result);
|
||||
|
||||
// Obtiene el directorio home del usuario
|
||||
std::string getHomeDirectory();
|
||||
|
||||
// Obtiene el directorio temporal del sistema
|
||||
std::string getTempDirectory();
|
||||
|
||||
} // namespace SystemUtils
|
||||
Reference in New Issue
Block a user