diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..69ee6ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# archivos de cmake +CMakeFiles/ +build/ +CMakeCache.txt +cmake_install.cmake +install_manifest.txt + +# compilados +*.so +*.dll +Makefile + +# Otros +temp/ +temp.* +test.* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..70d2183 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,77 @@ +################################################################################ +# Para mas información de este archivo visite la pagina de cmake: +# https://cmake.org/documentation/ +################################################################################ + +#Establece la versión mínima requerida de cmake para un proyecto. +cmake_minimum_required(VERSION 3.0.2) + +#Establece un nombre para el proyecto +project (latino-libnucleoex) + +option(MODO_SEGURO_FORZADO "Usar modo seguro forzado" OFF) +option(MODO_SEGURO "Usar modo seguro" OFF) + +if(MODO_SEGURO_FORZADO) + add_definitions(-DMODO_SEGURO_FORZADO) +elseif(MODO_SEGURO) + add_definitions(-DMODO_SEGURO) +endif() + +if(WIN32) + # Arquitectura del build + set(TARGET_ARCH_REGEX "^.*-march[= ]([^ ]+).*$") + string(REGEX MATCH "${TARGET_ARCH_REGEX}" TARGET_ARCH_MATCH "" "" ${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}) + if(TARGET_ARCH_MATCH) + string(REGEX REPLACE "${TARGET_ARCH_REGEX}" "\\1" TARGET_ARCH ${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS}) + else() + set(TARGET_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR}) + endif() + + # Establecer paths donde se instalo latino + set(LATINO_PATH "$ENV{LATINO_PATH}/bin" CACHE FILEPATH "Ruta de instalacion de latino.exe") + set(LATINO_LIBC "$ENV{LATINO_LIBC}" CACHE FILEPATH "Ruta de instalacion de latino.dll") + set(LATINO_INCLUDE "$ENV{LATINO_PATH}/include" CACHE FILEPATH "Ruta de instalacion de latino/include") + + # Enlazar + include_directories(${LATINO_INCLUDE} "include") + link_directories(${LATINO_PATH}) + + message(STATUS "TARGET_ARCH: ${TARGET_ARCH}") + message(STATUS "LATINO_PATH: ${LATINO_PATH}") + message(STATUS "LATINO_INCLUDE: ${LATINO_INCLUDE}") + message(STATUS "LATINO_LIBC: ${LATINO_LIBC}") +else() + include_directories("include") +endif() + +# msys +if(MSYS) + # Path en donde esta instalado latino + LINK_DIRECTORIES("/d/work/lenguaje-latino/latino/msys2") +endif() + +set(SRC_FILES src/latino-libnucleoex.c src/latino-libtipos.c src/latino-libruta.c src/latino-libes.c) + +#Agrega una biblioteca al proyecto utilizando los +if(MINGW) + #archivos de origen especificados. + set(CMAKE_SHARED_LIBRARY_PREFIX "") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--allow-multiple-definition") + add_library(latino-libnucleoex SHARED ${SRC_FILES}) + target_link_libraries(latino-libnucleoex ${LATINO_PATH}/latino.dll) +else() + #archivos de origen especificados. + add_library(latino-libnucleoex SHARED ${SRC_FILES}) + + #Vincula un objetivo a bibliotecas determinadas. + target_link_libraries(latino-libnucleoex latino) +endif() + +#Especifica las reglas que se ejecutarán en el momento de la instalación. +# Especifica las reglas que se ejecutarán en el momento de la instalación. +if(WIN32) + install(TARGETS latino-libnucleoex DESTINATION ${LATINO_PATH}) +else() + install(TARGETS latino-libnucleoex DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) +endif() \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..103404b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 FrankC64 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..bc1be39 --- /dev/null +++ b/README.md @@ -0,0 +1,165 @@ +# latino-lib-nucleoex +latino-lib-nucleoex es una extensión para Latino, la cual integra más funciones para expandir las capacidades del lenguaje. + + +## Tabla de contenidos +* [Tabla de contenidos](#tabla) + * [Instalación](#instalacion) + * [Instalación (LAP)](#instalacion_lap) + * [Instalación manual](#instalacion_manual) + * [Compilación](#compilacion) + * [Windows](#windows) + * [MinGW](#mingw) + * [Visual Studio](#visual_studio) + * [Linux](#linux) + * [Wiki](#wiki) + + +## Instalación +Antes de comenzar, debe saber que la instalación **SIN COMPILACIÓN** es exclusivamente para la versión **1.4.0** de Latino en **Windows**, por lo que si usted tiene una versión superior o inferior o se encuentra en un sistema que no sea Windows debe consultar el apartado de [compilación](#compilacion). + + +### Instalación (LAP) +El primer método de instalación es a través del administrador de paquetes **LAP**. Antes de continuar debe tener **Python** instalado. + +**1-** Instalamos el administrador de paquetes con **pip**. +```Batch +pip install LAP-latino-client +``` + +**2-** Nos ubicamos en la carpeta donde está nuestro proyecto, en caso contrario la librería será instalada fuera del alcance de Latino. + +**3-** Utilizamos **LAP** para instalar la librería. +```Batch +python -m LAP instalar latino-lib-nucleox +``` + +**4-** En la parte superior de su script de Latino ponga lo siguiente: +```Latino +incluir("libnucleoex") +``` + +Y ya está todo listo para utilizar la librería. + + +### Instalación manual +Aquí se muestra paso a paso la forma de instalar la librería en caso de no tener **Python** o no querer utilizar el administrador de paquetes **LAP**. + +**1-** Haga click [aquí](https://github.com/FrankC64/latino-lib-nucleox/releases/latest/download/latino-lib-nucleox.zip) para descargar la última versión. + +**2-** Vaya a la carpeta de instalación de Latino y en la subcaperta "bin" extraiga **latino-libnucleoex.dll**. + +**3-** En la parte superior de su script de Latino ponga lo siguiente: +```Latino +incluir("libnucleoex") +``` + +Y ya está todo listo para utilizar la librería. + + +## Compilación + + +### Windows + +**Requisitos:** +* Tener instalado [cmake](https://cmake.org/download/). +* Tener instalado [git](https://git-scm.com/download/win). +* Tener la siguiente variable de entorno: + ``` + LATINO_PATH=C:\ruta_de_instalacion_de_latino + ``` + En caso de no tenerla deberá agregarla en las variables de entorno de Windows. + + +**Compilación (MinGW):**
+Ejecutar lo siguiente en su consola/terminal: + +``` +git clone https://github.com/FrankC64/latino-lib-nucleoex.git +cd latino-lib-nucleoex +mkdir build +cd build +cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release ..\ +mingw32-make install +``` + + +**Compilación (Visual Studio):**
+Ejecutar lo siguiente en su consola/terminal: + +``` +git clone https://github.com/FrankC64/latino-lib-nucleoex.git +cd latino-lib-nucleoex +mkdir build +cd build +cmake -G "Visual Studio 17 2022" -DCMAKE_BUILD_TYPE=Release ..\ +cmake --build . --target install --config Release +``` + + +### Linux + +**Requisitos:**
+Antes de comenzar ejecute uno de los siguientes comandos en la terminal dependiendo de su sistema: +* Debian / Ubuntu + ```Bash + sudo apt-get install cmake git + ``` +* Arch + ```Bash + sudo pacman -S cmake git + ``` +* Fedora / CentOS + ```Bash + sudo dnf -y install cmake git + ``` + +**Compilación:**
+Ejecutar lo siguiente en la terminal: + +``` +git clone https://github.com/FrankC64/latino-lib-nucleoex.git +cd latino-lib-nucleoex +mkdir build +cd build +cmake -DCMAKE_BUILD_TYPE=Release ../ +sudo make install +``` + + +## Wiki +Click [aquí](https://github.com/FrankC64/latino-lib-nucleox/wiki) para conocer las funciones de la librería. + +## Preguntas y respuestas +\- **¿Qué es el modo seguro?**
+Como actualmente no existe la forma de controlar errores y excepciones en Latino se implementó una funcionalidad para evitar que los errores producidos por la librería detenga el funcionamiento del código y el programador pueda tomar una decisión de qué hacer en caso de que se produzcan estos errores. + +\- **¿Cómo compilo la librería para usar el modo seguro de forma predeterminada o forzada?**
+Al momento de utilizar el comando **cmake** ponga como instrucción lo siguiente: +``` +-DMODO_SEGURO=1 +``` + +en caso de que quiera que por defecto el modo seguro esté habilitado y + +``` +-DMODO_SEGURO_FORZADO=1 +``` + +en caso de que desee que el modo seguro esté siempre habilitado y no se pueda modificar desde Latino. + +\- **Estoy usando Linux y Latino no carga la librería.**
+Si esto le sucede deberá escribir el siguiente comando en su terminal: + +``` +export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH +``` + +Y el problema será solucionado. Si quiere una solución definitiva ejecute el siguiente comando: + +``` +echo 'export LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH"' >> ~/.profile +``` + +Y reinicie su sistema para que se aplique el cambio correctamente. diff --git a/ejemplo.lat b/ejemplo.lat new file mode 100644 index 0000000..36d66a3 --- /dev/null +++ b/ejemplo.lat @@ -0,0 +1,13 @@ +// incluye el modulo en latino +incluir("libnucleoex") + +libes.imprimir("libnucleoex versión: " .. libnucleoex.version() .. "\n") + +imprimir("Creamos test.") +libruta.crear_dir("test") + +imprimir("test existe: " .. libruta.existe("test")) + +imprimir("Eliminanos a test.") +libruta.remover_dir("test") +imprimir("test existe: " .. libruta.existe("test")) diff --git a/include/MSVC/dirent.h b/include/MSVC/dirent.h new file mode 100644 index 0000000..557485a --- /dev/null +++ b/include/MSVC/dirent.h @@ -0,0 +1,1212 @@ +/* + * Dirent interface for Microsoft Visual Studio + * + * Copyright (C) 1998-2019 Toni Ronkko + * This file is part of dirent. Dirent may be freely distributed + * under the MIT license. For all details and documentation, see + * https://github.com/tronkko/dirent + */ +#ifndef DIRENT_H +#define DIRENT_H + +/* Hide warnings about unreferenced local functions */ +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wunused-function" +#elif defined(_MSC_VER) +# pragma warning(disable:4505) +#elif defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wunused-function" +#endif + +/* + * Include windows.h without Windows Sockets 1.1 to prevent conflicts with + * Windows Sockets 2.0. + */ +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Indicates that d_type field is available in dirent structure */ +#define _DIRENT_HAVE_D_TYPE + +/* Indicates that d_namlen field is available in dirent structure */ +#define _DIRENT_HAVE_D_NAMLEN + +/* Entries missing from MSVC 6.0 */ +#if !defined(FILE_ATTRIBUTE_DEVICE) +# define FILE_ATTRIBUTE_DEVICE 0x40 +#endif + +/* File type and permission flags for stat(), general mask */ +#if !defined(S_IFMT) +# define S_IFMT _S_IFMT +#endif + +/* Directory bit */ +#if !defined(S_IFDIR) +# define S_IFDIR _S_IFDIR +#endif + +/* Character device bit */ +#if !defined(S_IFCHR) +# define S_IFCHR _S_IFCHR +#endif + +/* Pipe bit */ +#if !defined(S_IFFIFO) +# define S_IFFIFO _S_IFFIFO +#endif + +/* Regular file bit */ +#if !defined(S_IFREG) +# define S_IFREG _S_IFREG +#endif + +/* Read permission */ +#if !defined(S_IREAD) +# define S_IREAD _S_IREAD +#endif + +/* Write permission */ +#if !defined(S_IWRITE) +# define S_IWRITE _S_IWRITE +#endif + +/* Execute permission */ +#if !defined(S_IEXEC) +# define S_IEXEC _S_IEXEC +#endif + +/* Pipe */ +#if !defined(S_IFIFO) +# define S_IFIFO _S_IFIFO +#endif + +/* Block device */ +#if !defined(S_IFBLK) +# define S_IFBLK 0 +#endif + +/* Link */ +#if !defined(S_IFLNK) +# define S_IFLNK 0 +#endif + +/* Socket */ +#if !defined(S_IFSOCK) +# define S_IFSOCK 0 +#endif + +/* Read user permission */ +#if !defined(S_IRUSR) +# define S_IRUSR S_IREAD +#endif + +/* Write user permission */ +#if !defined(S_IWUSR) +# define S_IWUSR S_IWRITE +#endif + +/* Execute user permission */ +#if !defined(S_IXUSR) +# define S_IXUSR 0 +#endif + +/* Read group permission */ +#if !defined(S_IRGRP) +# define S_IRGRP 0 +#endif + +/* Write group permission */ +#if !defined(S_IWGRP) +# define S_IWGRP 0 +#endif + +/* Execute group permission */ +#if !defined(S_IXGRP) +# define S_IXGRP 0 +#endif + +/* Read others permission */ +#if !defined(S_IROTH) +# define S_IROTH 0 +#endif + +/* Write others permission */ +#if !defined(S_IWOTH) +# define S_IWOTH 0 +#endif + +/* Execute others permission */ +#if !defined(S_IXOTH) +# define S_IXOTH 0 +#endif + +/* Maximum length of file name */ +#if !defined(PATH_MAX) +# define PATH_MAX MAX_PATH +#endif +#if !defined(FILENAME_MAX) +# define FILENAME_MAX MAX_PATH +#endif +#if !defined(NAME_MAX) +# define NAME_MAX FILENAME_MAX +#endif + +/* File type flags for d_type */ +#define DT_UNKNOWN 0 +#define DT_REG S_IFREG +#define DT_DIR S_IFDIR +#define DT_FIFO S_IFIFO +#define DT_SOCK S_IFSOCK +#define DT_CHR S_IFCHR +#define DT_BLK S_IFBLK +#define DT_LNK S_IFLNK + +/* Macros for converting between st_mode and d_type */ +#define IFTODT(mode) ((mode) & S_IFMT) +#define DTTOIF(type) (type) + +/* + * File type macros. Note that block devices, sockets and links cannot be + * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are + * only defined for compatibility. These macros should always return false + * on Windows. + */ +#if !defined(S_ISFIFO) +# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) +#endif +#if !defined(S_ISDIR) +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#endif +#if !defined(S_ISREG) +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif +#if !defined(S_ISLNK) +# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#endif +#if !defined(S_ISSOCK) +# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) +#endif +#if !defined(S_ISCHR) +# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#endif +#if !defined(S_ISBLK) +# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) +#endif + +/* Return the exact length of the file name without zero terminator */ +#define _D_EXACT_NAMLEN(p) ((p)->d_namlen) + +/* Return the maximum size of a file name */ +#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Wide-character version */ +struct _wdirent { + /* Always zero */ + long d_ino; + + /* Position of next file in a directory stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + wchar_t d_name[PATH_MAX+1]; +}; +typedef struct _wdirent _wdirent; + +struct _WDIR { + /* Current directory entry */ + struct _wdirent ent; + + /* Private file data */ + WIN32_FIND_DATAW data; + + /* True if data is valid */ + int cached; + + /* True if next entry is invalid */ + int invalid; + + /* Win32 search handle */ + HANDLE handle; + + /* Initial directory name */ + wchar_t *patt; +}; +typedef struct _WDIR _WDIR; + +/* Multi-byte character version */ +struct dirent { + /* Always zero */ + long d_ino; + + /* Position of next file in a directory stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + char d_name[PATH_MAX+1]; +}; +typedef struct dirent dirent; + +struct DIR { + struct dirent ent; + struct _WDIR *wdirp; +}; +typedef struct DIR DIR; + + +/* Dirent functions */ +static DIR *opendir(const char *dirname); +static _WDIR *_wopendir(const wchar_t *dirname); + +static struct dirent *readdir(DIR *dirp); +static struct _wdirent *_wreaddir(_WDIR *dirp); + +static int readdir_r( + DIR *dirp, struct dirent *entry, struct dirent **result); +static int _wreaddir_r( + _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); + +static int closedir(DIR *dirp); +static int _wclosedir(_WDIR *dirp); + +static void rewinddir(DIR *dirp); +static void _wrewinddir(_WDIR *dirp); + +static long telldir(DIR *dirp); +static long _wtelldir(_WDIR *dirp); + +static void seekdir(DIR *dirp, long loc); +static void _wseekdir(_WDIR *dirp, long loc); + +static int scandir(const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)); + +static int alphasort(const struct dirent **a, const struct dirent **b); + +static int versionsort(const struct dirent **a, const struct dirent **b); + +static int strverscmp(const char *a, const char *b); + +/* For compatibility with Symbian */ +#define wdirent _wdirent +#define WDIR _WDIR +#define wopendir _wopendir +#define wreaddir _wreaddir +#define wclosedir _wclosedir +#define wrewinddir _wrewinddir +#define wtelldir _wtelldir +#define wseekdir _wseekdir + +/* Compatibility with older Microsoft compilers and non-Microsoft compilers */ +#if !defined(_MSC_VER) || _MSC_VER < 1400 +# define wcstombs_s dirent_wcstombs_s +# define mbstowcs_s dirent_mbstowcs_s +#endif + +/* Optimize dirent_set_errno() away on modern Microsoft compilers */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 +# define dirent_set_errno _set_errno +#endif + + +/* Internal utility functions */ +static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp); +static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp); +static long dirent_hash(WIN32_FIND_DATAW *datap); + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static int dirent_mbstowcs_s( + size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, + const char *mbstr, size_t count); +#endif + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static int dirent_wcstombs_s( + size_t *pReturnValue, char *mbstr, size_t sizeInBytes, + const wchar_t *wcstr, size_t count); +#endif + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static void dirent_set_errno(int error); +#endif + + +/* + * Open directory stream DIRNAME for read and return a pointer to the + * internal working area that is used to retrieve individual directory + * entries. + */ +static _WDIR * +_wopendir(const wchar_t *dirname) +{ + wchar_t *p; + + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno(ENOENT); + return NULL; + } + + /* Allocate new _WDIR structure */ + _WDIR *dirp = (_WDIR*) malloc(sizeof(struct _WDIR)); + if (!dirp) + return NULL; + + /* Reset _WDIR structure */ + dirp->handle = INVALID_HANDLE_VALUE; + dirp->patt = NULL; + dirp->cached = 0; + dirp->invalid = 0; + + /* + * Compute the length of full path plus zero terminator + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + /* Desktop */ + DWORD n = GetFullPathNameW(dirname, 0, NULL, NULL); +#else + /* WinRT */ + size_t n = wcslen(dirname); +#endif + + /* Allocate room for absolute directory name and search pattern */ + dirp->patt = (wchar_t*) malloc(sizeof(wchar_t) * n + 16); + if (dirp->patt == NULL) + goto exit_closedir; + + /* + * Convert relative directory name to an absolute one. This + * allows rewinddir() to function correctly even when current + * working directory is changed between opendir() and rewinddir(). + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + /* Desktop */ + n = GetFullPathNameW(dirname, n, dirp->patt, NULL); + if (n <= 0) + goto exit_closedir; +#else + /* WinRT */ + wcsncpy_s(dirp->patt, n+1, dirname, n); +#endif + + /* Append search pattern \* to the directory name */ + p = dirp->patt + n; + switch (p[-1]) { + case '\\': + case '/': + case ':': + /* Directory ends in path separator, e.g. c:\temp\ */ + /*NOP*/; + break; + + default: + /* Directory name doesn't end in path separator */ + *p++ = '\\'; + } + *p++ = '*'; + *p = '\0'; + + /* Open directory stream and retrieve the first entry */ + if (!dirent_first(dirp)) + goto exit_closedir; + + /* Success */ + return dirp; + + /* Failure */ +exit_closedir: + _wclosedir(dirp); + return NULL; +} + +/* + * Read next directory entry. + * + * Returns pointer to static directory entry which may be overwritten by + * subsequent calls to _wreaddir(). + */ +static struct _wdirent * +_wreaddir(_WDIR *dirp) +{ + /* + * Read directory entry to buffer. We can safely ignore the return + * value as entry will be set to NULL in case of error. + */ + struct _wdirent *entry; + (void) _wreaddir_r(dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry. + * + * Returns zero on success. If end of directory stream is reached, then sets + * result to NULL and returns zero. + */ +static int +_wreaddir_r( + _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result) +{ + /* Validate directory handle */ + if (!dirp || dirp->handle == INVALID_HANDLE_VALUE || !dirp->patt) { + dirent_set_errno(EBADF); + *result = NULL; + return -1; + } + + /* Read next directory entry */ + WIN32_FIND_DATAW *datap = dirent_next(dirp); + if (!datap) { + /* Return NULL to indicate end of directory */ + *result = NULL; + return /*OK*/0; + } + + /* + * Copy file name as wide-character string. If the file name is too + * long to fit in to the destination buffer, then truncate file name + * to PATH_MAX characters and zero-terminate the buffer. + */ + size_t i = 0; + while (i < PATH_MAX && datap->cFileName[i] != 0) { + entry->d_name[i] = datap->cFileName[i]; + i++; + } + entry->d_name[i] = 0; + + /* Length of file name excluding zero terminator */ + entry->d_namlen = i; + + /* Determine file type */ + DWORD attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) + entry->d_type = DT_CHR; + else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) + entry->d_type = DT_DIR; + else + entry->d_type = DT_REG; + + /* Read the next directory entry to cache */ + datap = dirent_next(dirp); + if (datap) { + /* Compute 31-bit hash of the next directory entry */ + entry->d_off = dirent_hash(datap); + + /* Push the next directory entry back to cache */ + dirp->cached = 1; + } else { + /* End of directory stream */ + entry->d_off = (long) ((~0UL) >> 1); + } + + /* Reset other fields */ + entry->d_ino = 0; + entry->d_reclen = sizeof(struct _wdirent); + + /* Set result address */ + *result = entry; + return /*OK*/0; +} + +/* + * Close directory stream opened by opendir() function. This invalidates the + * DIR structure as well as any directory entry read previously by + * _wreaddir(). + */ +static int +_wclosedir(_WDIR *dirp) +{ + if (!dirp) { + dirent_set_errno(EBADF); + return /*failure*/-1; + } + + /* + * Release search handle if we have one. Being able to handle + * partially initialized _WDIR structure allows us to use this + * function to handle errors occuring within _wopendir. + */ + if (dirp->handle != INVALID_HANDLE_VALUE) { + FindClose(dirp->handle); + } + + /* + * Release search pattern. Note that we don't need to care if + * dirp->patt is NULL or not: function free is guaranteed to act + * appropriately. + */ + free(dirp->patt); + + /* Release directory structure */ + free(dirp); + return /*success*/0; +} + +/* + * Rewind directory stream such that _wreaddir() returns the very first + * file name again. + */ +static void _wrewinddir(_WDIR* dirp) +{ + /* Check directory pointer */ + if (!dirp || dirp->handle == INVALID_HANDLE_VALUE || !dirp->patt) + return; + + /* Release existing search handle */ + FindClose(dirp->handle); + + /* Open new search handle */ + dirent_first(dirp); +} + +/* Get first directory entry */ +static WIN32_FIND_DATAW * +dirent_first(_WDIR *dirp) +{ + /* Open directory and retrieve the first entry */ + dirp->handle = FindFirstFileExW( + dirp->patt, FindExInfoStandard, &dirp->data, + FindExSearchNameMatch, NULL, 0); + if (dirp->handle == INVALID_HANDLE_VALUE) + goto error; + + /* A directory entry is now waiting in memory */ + dirp->cached = 1; + return &dirp->data; + +error: + /* Failed to open directory: no directory entry in memory */ + dirp->cached = 0; + dirp->invalid = 1; + + /* Set error code */ + DWORD errorcode = GetLastError(); + switch (errorcode) { + case ERROR_ACCESS_DENIED: + /* No read access to directory */ + dirent_set_errno(EACCES); + break; + + case ERROR_DIRECTORY: + /* Directory name is invalid */ + dirent_set_errno(ENOTDIR); + break; + + case ERROR_PATH_NOT_FOUND: + default: + /* Cannot find the file */ + dirent_set_errno(ENOENT); + } + return NULL; +} + +/* Get next directory entry */ +static WIN32_FIND_DATAW * +dirent_next(_WDIR *dirp) +{ + /* Return NULL if seek position was invalid */ + if (dirp->invalid) + return NULL; + + /* Is the next directory entry already in cache? */ + if (dirp->cached) { + /* Yes, a valid directory entry found in memory */ + dirp->cached = 0; + return &dirp->data; + } + + /* Read the next directory entry from stream */ + if (FindNextFileW(dirp->handle, &dirp->data) == FALSE) { + /* End of directory stream */ + return NULL; + } + + /* Success */ + return &dirp->data; +} + +/* + * Compute 31-bit hash of file name. + * + * See djb2 at http://www.cse.yorku.ca/~oz/hash.html + */ +static long +dirent_hash(WIN32_FIND_DATAW *datap) +{ + unsigned long hash = 5381; + unsigned long c; + const wchar_t *p = datap->cFileName; + const wchar_t *e = p + MAX_PATH; + while (p != e && (c = *p++) != 0) { + hash = (hash << 5) + hash + c; + } + + return (long) (hash & ((~0UL) >> 1)); +} + +/* Open directory stream using plain old C-string */ +static DIR *opendir(const char *dirname) +{ + /* Must have directory name */ + if (dirname == NULL || dirname[0] == '\0') { + dirent_set_errno(ENOENT); + return NULL; + } + + /* Allocate memory for DIR structure */ + struct DIR *dirp = (DIR*) malloc(sizeof(struct DIR)); + if (!dirp) + return NULL; + + /* Convert directory name to wide-character string */ + wchar_t wname[PATH_MAX + 1]; + size_t n; + int error = mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX+1); + if (error) + goto exit_failure; + + /* Open directory stream using wide-character name */ + dirp->wdirp = _wopendir(wname); + if (!dirp->wdirp) + goto exit_failure; + + /* Success */ + return dirp; + + /* Failure */ +exit_failure: + free(dirp); + return NULL; +} + +/* Read next directory entry */ +static struct dirent * +readdir(DIR *dirp) +{ + /* + * Read directory entry to buffer. We can safely ignore the return + * value as entry will be set to NULL in case of error. + */ + struct dirent *entry; + (void) readdir_r(dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry into called-allocated buffer. + * + * Returns zero on success. If the end of directory stream is reached, then + * sets result to NULL and returns zero. + */ +static int +readdir_r( + DIR *dirp, struct dirent *entry, struct dirent **result) +{ + /* Read next directory entry */ + WIN32_FIND_DATAW *datap = dirent_next(dirp->wdirp); + if (!datap) { + /* No more directory entries */ + *result = NULL; + return /*OK*/0; + } + + /* Attempt to convert file name to multi-byte string */ + size_t n; + int error = wcstombs_s( + &n, entry->d_name, PATH_MAX + 1, + datap->cFileName, PATH_MAX + 1); + + /* + * If the file name cannot be represented by a multi-byte string, then + * attempt to use old 8+3 file name. This allows the program to + * access files although file names may seem unfamiliar to the user. + * + * Be ware that the code below cannot come up with a short file name + * unless the file system provides one. At least VirtualBox shared + * folders fail to do this. + */ + if (error && datap->cAlternateFileName[0] != '\0') { + error = wcstombs_s( + &n, entry->d_name, PATH_MAX + 1, + datap->cAlternateFileName, PATH_MAX + 1); + } + + if (!error) { + /* Length of file name excluding zero terminator */ + entry->d_namlen = n - 1; + + /* Determine file type */ + DWORD attr = datap->dwFileAttributes; + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) + entry->d_type = DT_CHR; + else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) + entry->d_type = DT_DIR; + else + entry->d_type = DT_REG; + + /* Get offset of next file */ + datap = dirent_next(dirp->wdirp); + if (datap) { + /* Compute 31-bit hash of the next directory entry */ + entry->d_off = dirent_hash(datap); + + /* Push the next directory entry back to cache */ + dirp->wdirp->cached = 1; + } else { + /* End of directory stream */ + entry->d_off = (long) ((~0UL) >> 1); + } + + /* Reset fields */ + entry->d_ino = 0; + entry->d_reclen = sizeof(struct dirent); + } else { + /* + * Cannot convert file name to multi-byte string so construct + * an erroneous directory entry and return that. Note that + * we cannot return NULL as that would stop the processing + * of directory entries completely. + */ + entry->d_name[0] = '?'; + entry->d_name[1] = '\0'; + entry->d_namlen = 1; + entry->d_type = DT_UNKNOWN; + entry->d_ino = 0; + entry->d_off = -1; + entry->d_reclen = 0; + } + + /* Return pointer to directory entry */ + *result = entry; + return /*OK*/0; +} + +/* Close directory stream */ +static int +closedir(DIR *dirp) +{ + int ok; + + if (!dirp) + goto exit_failure; + + /* Close wide-character directory stream */ + ok = _wclosedir(dirp->wdirp); + dirp->wdirp = NULL; + + /* Release multi-byte character version */ + free(dirp); + return ok; + +exit_failure: + /* Invalid directory stream */ + dirent_set_errno(EBADF); + return /*failure*/-1; +} + +/* Rewind directory stream to beginning */ +static void +rewinddir(DIR *dirp) +{ + if (!dirp) + return; + + /* Rewind wide-character string directory stream */ + _wrewinddir(dirp->wdirp); +} + +/* Get position of directory stream */ +static long +_wtelldir(_WDIR *dirp) +{ + if (!dirp || dirp->handle == INVALID_HANDLE_VALUE) { + dirent_set_errno(EBADF); + return /*failure*/-1; + } + + /* Read next file entry */ + WIN32_FIND_DATAW *datap = dirent_next(dirp); + if (!datap) { + /* End of directory stream */ + return (long) ((~0UL) >> 1); + } + + /* Store file entry to cache for readdir() */ + dirp->cached = 1; + + /* Return the 31-bit hash code to be used as stream position */ + return dirent_hash(datap); +} + +/* Get position of directory stream */ +static long +telldir(DIR *dirp) +{ + if (!dirp) { + dirent_set_errno(EBADF); + return -1; + } + + return _wtelldir(dirp->wdirp); +} + +/* Seek directory stream to offset */ +static void +_wseekdir(_WDIR *dirp, long loc) +{ + /* Directory must be open */ + if (!dirp || dirp->handle == INVALID_HANDLE_VALUE) + goto exit_failure; + + /* Ensure that seek position is valid */ + if (loc < 0) + goto exit_failure; + + /* Restart directory stream from the beginning */ + FindClose(dirp->handle); + if (!dirent_first(dirp)) + goto exit_failure; + + /* Reset invalid flag so that we can read from the stream again */ + dirp->invalid = 0; + + /* + * Read directory entries from the beginning until the hash matches a + * file name. Be ware that hash code is only 31 bits longs and + * duplicates are possible: the hash code cannot return the position + * with 100.00% accuracy! Moreover, the method is slow for large + * directories. + */ + long hash; + do { + /* Read next directory entry */ + WIN32_FIND_DATAW *datap = dirent_next(dirp); + if (!datap) { + /* + * End of directory stream was reached before finding + * the requested location. Perhaps the file in + * question was deleted or moved out of the directory. + */ + goto exit_failure; + } + + /* Does the file name match the hash? */ + hash = dirent_hash(datap); + } while (hash != loc); + + /* + * File name matches the hash! Push the directory entry back to cache + * from where next readdir() will return it. + */ + dirp->cached = 1; + dirp->invalid = 0; + return; + +exit_failure: + /* Ensure that readdir will return NULL */ + dirp->invalid = 1; +} + +/* Seek directory stream to offset */ +static void +seekdir(DIR *dirp, long loc) +{ + if (!dirp) + return; + + _wseekdir(dirp->wdirp, loc); +} + +/* Scan directory for entries */ +static int +scandir( + const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)) +{ + int result; + + /* Open directory stream */ + DIR *dir = opendir(dirname); + if (!dir) { + /* Cannot open directory */ + return /*Error*/ -1; + } + + /* Read directory entries to memory */ + struct dirent *tmp = NULL; + struct dirent **files = NULL; + size_t size = 0; + size_t allocated = 0; + while (1) { + /* Allocate room for a temporary directory entry */ + if (!tmp) { + tmp = (struct dirent*) malloc(sizeof(struct dirent)); + if (!tmp) + goto exit_failure; + } + + /* Read directory entry to temporary area */ + struct dirent *entry; + if (readdir_r(dir, tmp, &entry) != /*OK*/0) + goto exit_failure; + + /* Stop if we already read the last directory entry */ + if (entry == NULL) + goto exit_success; + + /* Determine whether to include the entry in results */ + if (filter && !filter(tmp)) + continue; + + /* Enlarge pointer table to make room for another pointer */ + if (size >= allocated) { + /* Compute number of entries in the new table */ + size_t num_entries = size * 2 + 16; + + /* Allocate new pointer table or enlarge existing */ + void *p = realloc(files, sizeof(void*) * num_entries); + if (!p) + goto exit_failure; + + /* Got the memory */ + files = (dirent**) p; + allocated = num_entries; + } + + /* Store the temporary entry to ptr table */ + files[size++] = tmp; + tmp = NULL; + } + +exit_failure: + /* Release allocated entries */ + for (size_t i = 0; i < size; i++) { + free(files[i]); + } + + /* Release the pointer table */ + free(files); + files = NULL; + + /* Exit with error code */ + result = /*error*/ -1; + goto exit_status; + +exit_success: + /* Sort directory entries */ + qsort(files, size, sizeof(void*), + (int (*) (const void*, const void*)) compare); + + /* Pass pointer table to caller */ + if (namelist) + *namelist = files; + + /* Return the number of directory entries read */ + result = (int) size; + +exit_status: + /* Release temporary directory entry, if we had one */ + free(tmp); + + /* Close directory stream */ + closedir(dir); + return result; +} + +/* Alphabetical sorting */ +static int +alphasort(const struct dirent **a, const struct dirent **b) +{ + return strcoll((*a)->d_name, (*b)->d_name); +} + +/* Sort versions */ +static int +versionsort(const struct dirent **a, const struct dirent **b) +{ + return strverscmp((*a)->d_name, (*b)->d_name); +} + +/* Compare strings */ +static int +strverscmp(const char *a, const char *b) +{ + size_t i = 0; + size_t j; + + /* Find first difference */ + while (a[i] == b[i]) { + if (a[i] == '\0') { + /* No difference */ + return 0; + } + ++i; + } + + /* Count backwards and find the leftmost digit */ + j = i; + while (j > 0 && isdigit(a[j-1])) { + --j; + } + + /* Determine mode of comparison */ + if (a[j] == '0' || b[j] == '0') { + /* Find the next non-zero digit */ + while (a[j] == '0' && a[j] == b[j]) { + j++; + } + + /* String with more digits is smaller, e.g 002 < 01 */ + if (isdigit(a[j])) { + if (!isdigit(b[j])) { + return -1; + } + } else if (isdigit(b[j])) { + return 1; + } + } else if (isdigit(a[j]) && isdigit(b[j])) { + /* Numeric comparison */ + size_t k1 = j; + size_t k2 = j; + + /* Compute number of digits in each string */ + while (isdigit(a[k1])) { + k1++; + } + while (isdigit(b[k2])) { + k2++; + } + + /* Number with more digits is bigger, e.g 999 < 1000 */ + if (k1 < k2) + return -1; + else if (k1 > k2) + return 1; + } + + /* Alphabetical comparison */ + return (int) ((unsigned char) a[i]) - ((unsigned char) b[i]); +} + +/* Convert multi-byte string to wide character string */ +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static int +dirent_mbstowcs_s( + size_t *pReturnValue, wchar_t *wcstr, + size_t sizeInWords, const char *mbstr, size_t count) +{ + /* Older Visual Studio or non-Microsoft compiler */ + size_t n = mbstowcs(wcstr, mbstr, sizeInWords); + if (wcstr && n >= count) + return /*error*/ 1; + + /* Zero-terminate output buffer */ + if (wcstr && sizeInWords) { + if (n >= sizeInWords) + n = sizeInWords - 1; + wcstr[n] = 0; + } + + /* Length of multi-byte string with zero terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + return 0; +} +#endif + +/* Convert wide-character string to multi-byte string */ +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static int +dirent_wcstombs_s( + size_t *pReturnValue, char *mbstr, + size_t sizeInBytes, const wchar_t *wcstr, size_t count) +{ + /* Older Visual Studio or non-Microsoft compiler */ + size_t n = wcstombs(mbstr, wcstr, sizeInBytes); + if (mbstr && n >= count) + return /*error*/1; + + /* Zero-terminate output buffer */ + if (mbstr && sizeInBytes) { + if (n >= sizeInBytes) { + n = sizeInBytes - 1; + } + mbstr[n] = '\0'; + } + + /* Length of resulting multi-bytes string WITH zero-terminator */ + if (pReturnValue) { + *pReturnValue = n + 1; + } + + /* Success */ + return 0; +} +#endif + +/* Set errno variable */ +#if !defined(_MSC_VER) || _MSC_VER < 1400 +static void +dirent_set_errno(int error) +{ + /* Non-Microsoft compiler or older Microsoft compiler */ + errno = error; +} +#endif + +#ifdef __cplusplus +} +#endif +#endif /*DIRENT_H*/ diff --git a/include/latino-libes.h b/include/latino-libes.h new file mode 100644 index 0000000..1cbad8a --- /dev/null +++ b/include/latino-libes.h @@ -0,0 +1,17 @@ +#ifndef LATINO_LIBES +#define LATINO_LIBES + +#include + +#define LIBES "libes" + +void lat_imprimir(lat_mv *mv); + +static const lat_CReg lib_es[] = { + {"imprimir", lat_imprimir, 1}, + {"escribir", lat_imprimir, 1}, + {"poner", lat_imprimir, 1}, + {NULL, NULL, 0} +}; + +#endif diff --git a/include/latino-libnucleoex.h b/include/latino-libnucleoex.h new file mode 100644 index 0000000..204844f --- /dev/null +++ b/include/latino-libnucleoex.h @@ -0,0 +1,37 @@ +#ifndef LATINO_LIBNUCLEOEX +#define LATINO_LIBNUCLEOEX + +#define LIBNUCLEOEX_VERSION "0.0.1" + +#include +#include +#include +#include + +#define LIBNUCLEOEX "libnucleoex" + +extern bool modo_seguro; +extern char *ultimo_error; + +void generar_error(lat_mv *mv, char *error); +bool hay_mas_argumentos(lat_mv *mv); +char *arreglar_ruta(const char *ruta); + +void lat_establecer_modo_seguro(lat_mv *mv); +void lat_modo_seguro_estado(lat_mv *mv); +void lat_modo_seguro_forzado(lat_mv *mv); +void lat_ultimo_error(lat_mv *mv); +void lat_generar_error(lat_mv *mv); +void lat_version(lat_mv *mv); + +static const lat_CReg lib_nucleoex[] = { + {"establecer_modo_seguro", lat_establecer_modo_seguro, 1}, + {"modo_seguro_estado", lat_modo_seguro_estado, 0}, + {"modo_seguro_forzado", lat_modo_seguro_forzado, 0}, + {"ultimo_error", lat_ultimo_error, 0}, + {"generar_error", lat_generar_error, 1}, + {"version", lat_version, 0}, + {NULL, NULL, 0} +}; + +#endif diff --git a/include/latino-libruta.h b/include/latino-libruta.h new file mode 100644 index 0000000..49cf144 --- /dev/null +++ b/include/latino-libruta.h @@ -0,0 +1,42 @@ +#ifndef LATINO_LIBRUTA +#define LATINO_LIBRUTA + +#include + +#ifdef _WIN32 +#define RUTA_SEPARADOR '\\' +#else +#define RUTA_SEPARADOR '/' +#endif + +#define LIBRUTA "libruta" + +struct DirNodo { + char *elemento_nombre; + struct DirNodo *sig; +}; + +struct DirNodo *crear_dirnodo(); + +void lat_crear_dir(lat_mv *mv); +void lat_remover_dir(lat_mv *mv); +void lat_listar_dir(lat_mv *mv); +void lat_es_dir(lat_mv *mv); +void lat_es_archivo(lat_mv *mv); +void lat_existe(lat_mv *mv); + +static const lat_CReg lib_ruta[] = { + {"crear_dir", lat_crear_dir, 1}, + {"crear_directorio", lat_crear_dir, 1}, + {"remover_dir", lat_remover_dir, 2}, + {"remover_directorio", lat_remover_dir, 2}, + {"listar_dir", lat_listar_dir, 2}, + {"listar_directorio", lat_listar_dir, 2}, + {"existe", lat_existe, 1}, + {"es_dir", lat_es_dir, 1}, + {"es_directorio", lat_es_dir, 1}, + {"es_archivo", lat_es_archivo, 1}, + {NULL, NULL, 0} +}; + +#endif diff --git a/include/latino-libtipos.h b/include/latino-libtipos.h new file mode 100644 index 0000000..10ebe0d --- /dev/null +++ b/include/latino-libtipos.h @@ -0,0 +1,12 @@ +#ifndef LATINO_LIBTIPOS +#define LATINO_LIBTIPOS + +#include +#include + +#define LIBTIPOS "libtipos" + +int utf8_longitud(const char *cadena); +wchar_t *utf8_a_utf16(const char *cadena_utf8); + +#endif diff --git a/src/latino-libes.c b/src/latino-libes.c new file mode 100644 index 0000000..97e6792 --- /dev/null +++ b/src/latino-libes.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include +#include + +void lat_imprimir(lat_mv *mv) { + lat_objeto *obj = latC_desapilar(mv); + char *cadena = latC_checar_cadena(mv, obj); + + wchar_t *cadena_utf16 = utf8_a_utf16(cadena); + + if (!cadena_utf16) { + generar_error(mv, "La cadena de texto no puede ser impresa."); + } else { + +#ifdef _WIN32 + int modo_prev = _setmode(_fileno(stdout), _O_U8TEXT); + wprintf(L"%ls", cadena_utf16); + _setmode(_fileno(stdout), modo_prev); +#else + const char *locale_prev = setlocale(LC_CTYPE, NULL); + setlocale(LC_CTYPE, "en_US.UTF-8"); + wprintf(L"%ls", cadena_utf16); + setlocale(LC_CTYPE, locale_prev); +#endif + + free(cadena_utf16); + latC_apilar(mv, latC_crear_logico(mv, true)); + } +} diff --git a/src/latino-libnucleoex.c b/src/latino-libnucleoex.c new file mode 100644 index 0000000..ce00265 --- /dev/null +++ b/src/latino-libnucleoex.c @@ -0,0 +1,87 @@ +#ifdef _WIN32 +#define LATINO_BUILD_AS_DLL +#endif + +#define LATINO_LIB + +#include +#include +#include +#include + +#if (defined MODO_SEGURO_FORZADO) || (defined MODO_SEGURO) +bool modo_seguro = true; +#else +bool modo_seguro = false; +#endif + +char *ultimo_error = NULL; + +void generar_error(lat_mv *mv, char *error) { + if (modo_seguro) { + ultimo_error = error; + } else { + latC_error(mv, error); + } +} + +char *arreglar_ruta(const char *ruta) { + char *nueva_ruta = malloc(strlen(ruta) + 1); + strcpy(nueva_ruta, ruta); + + char reemplazar = RUTA_SEPARADOR == '/' ? '\\' : '/'; + + for (int i=0;nueva_ruta[i];i++) { + if (nueva_ruta[i] == reemplazar) { + nueva_ruta[i] = RUTA_SEPARADOR; + } + } + + return nueva_ruta; +} + +void lat_establecer_modo_seguro(lat_mv *mv) { + lat_objeto *obj = latC_desapilar(mv); + bool modo = latC_checar_logico(mv, obj); + + #ifndef MODO_SEGURO_FORZADO + modo_seguro = modo; + #endif +} + +void lat_modo_seguro_estado(lat_mv *mv) { + latC_apilar(mv, latC_crear_logico(mv, modo_seguro)); +} + +void lat_modo_seguro_forzado(lat_mv *mv) { + #ifdef MODO_SEGURO_FORZADO + latC_apilar(mv, latC_crear_logico(mv, true)); + #else + latC_apilar(mv, latC_crear_logico(mv, false)); + #endif +} + +void lat_ultimo_error(lat_mv *mv) { + if (ultimo_error) { + latC_apilar_string(mv, ultimo_error); + ultimo_error = NULL; + } else { + latC_apilar_string(mv, ""); + } +} + +void lat_generar_error(lat_mv *mv) { + lat_objeto *obj = latC_desapilar(mv); + char *error = latC_checar_cadena(mv, obj); + latC_error(mv, error); +} + +void lat_version(lat_mv *mv) { + latC_apilar(mv, latC_crear_cadena(mv, LIBNUCLEOEX_VERSION)); +} + +LATINO_API void latC_abrir_liblatino_libnucleoex(lat_mv *mv) { + latC_abrir_liblatino(mv, LIBNUCLEOEX, lib_nucleoex); + latC_abrir_liblatino(mv, LIBRUTA, lib_ruta); + latC_abrir_liblatino(mv, LIBES, lib_es); +} diff --git a/src/latino-libruta.c b/src/latino-libruta.c new file mode 100644 index 0000000..cdbb7d5 --- /dev/null +++ b/src/latino-libruta.c @@ -0,0 +1,310 @@ +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#include +#else +#include +#endif + +struct DirNodo *crear_dirnodo() { + struct DirNodo *dirnodo = (struct DirNodo*)malloc(sizeof(struct DirNodo)); + dirnodo->elemento_nombre = NULL; + dirnodo->sig = NULL; + return dirnodo; +} + +struct DirNodo *_listar_dir(const char* ruta) { + struct DirNodo *dirnodo = NULL; + struct DirNodo *siguiente; + + DIR *directorio = opendir(ruta); + struct dirent *entrada; + + if (directorio) { + while((entrada = readdir(directorio))){ + if (strcmp(entrada->d_name, ".") == 0 || strcmp(entrada->d_name, "..") == 0) { + continue; + } + + if (dirnodo) { + siguiente->sig = crear_dirnodo(); + siguiente = siguiente->sig; + } else { + dirnodo = crear_dirnodo(); + siguiente = dirnodo; + } + + siguiente->elemento_nombre = (char*)malloc(strlen(entrada->d_name) + 1); + strcpy(siguiente->elemento_nombre, entrada->d_name); + } + + dirnodo = (dirnodo) ? dirnodo : crear_dirnodo(); + closedir(directorio); + } + + return dirnodo; +} + +lista *listar_dir(lat_mv *mv, const char *ruta) { + lista *elementos = latL_crear(mv); + struct DirNodo *dir = _listar_dir(ruta); + + if (dir) { + if (dir->elemento_nombre) { + struct DirNodo *siguiente = dir; + + while (siguiente) { + lat_objeto *cadena = latC_crear_cadena(mv, siguiente->elemento_nombre); + latL_agregar(mv, elementos, cadena); + + dir = siguiente; + siguiente = siguiente->sig; + free(dir->elemento_nombre); + free(dir); + } + } else { + free(dir); + } + } else { + latL_destruir(mv, elementos); + ultimo_error = strerror(errno); + return NULL; + } + + return elementos; +} + +lista *listar_dir_recursivo(lat_mv *mv, const char *ruta) { + char *elemento_nombre, *ruta_siguiente; + lista *ruta_elementos, *elementos, *temp; + bool separador; + struct stat elemento_stat; + + lista *lista_elementos = listar_dir(mv, ruta); + if (!lista_elementos) return NULL; + + elementos = latL_crear(mv); + separador = ruta[strlen(ruta)-1] == RUTA_SEPARADOR; + ruta_elementos = latL_crear(mv); + + latL_agregar(mv, ruta_elementos, latC_crear_cadena(mv, ruta)); + latL_agregar(mv, ruta_elementos, latC_crear_lista(mv, lista_elementos)); + latL_agregar(mv, elementos, latC_crear_lista(mv, ruta_elementos)); + + LIST_FOREACH(lista_elementos, primero, siguiente, cur) { + elemento_nombre = getstr(getCadena((lat_objeto*)cur->valor)); + + ruta_siguiente = (char*)malloc( + strlen(ruta) + strlen(elemento_nombre) + + (separador ? 0:1) + 1 + ); + + if (separador) { + sprintf( + ruta_siguiente, "%s%s", + ruta, elemento_nombre); + } else { + sprintf( + ruta_siguiente, "%s%c%s", + ruta, RUTA_SEPARADOR, elemento_nombre); + } + + if (stat(ruta_siguiente, &elemento_stat)) { + free(ruta_siguiente); + continue; + } + + if (S_ISDIR(elemento_stat.st_mode)) { + temp = listar_dir_recursivo(mv, ruta_siguiente); + + if (!temp) { + latL_limpiar_destruir(mv, elementos); + free(ruta_siguiente); + return NULL; + } else { + latL_extender(mv, elementos, temp); + latL_destruir(mv, temp); + } + } + + free(ruta_siguiente); + } + + return elementos; +} + +void remover_dir_recursivo(const char *ruta) { + DIR *directorio; + struct dirent *entrada; + char *elemento_ruta; + struct stat elemento_stat; + bool separador; + + directorio = opendir(ruta); + separador = ruta[strlen(ruta)-1] == RUTA_SEPARADOR; + + if (directorio) { + while((entrada = readdir(directorio))){ + if (strcmp(entrada->d_name, ".") == 0 || strcmp(entrada->d_name, "..") == 0) { + continue; + } + + elemento_ruta = (char*)malloc( + strlen(ruta) + strlen(entrada->d_name) + + (separador ? 0:1) + 1 + ); + + if (separador) { + sprintf( + elemento_ruta, "%s%s", + ruta, entrada->d_name); + } else { + sprintf( + elemento_ruta, "%s%c%s", + ruta, RUTA_SEPARADOR, entrada->d_name); + } + + if (stat(elemento_ruta, &elemento_stat)) { + closedir(directorio); + free(elemento_ruta); + return; + } + + if (S_ISDIR(elemento_stat.st_mode)) { + remover_dir_recursivo(elemento_ruta); + } else { + remove(elemento_ruta); + } + + free(elemento_ruta); + } + + closedir(directorio); + rmdir(ruta); + } +} + +// Librería: + +void lat_crear_dir(lat_mv *mv) { + lat_objeto *obj = latC_desapilar(mv); + char *ruta = latC_checar_cadena(mv, obj); + + #ifdef _WIN32 + int result = mkdir(ruta); + #else + int result = mkdir(ruta, S_IRWXU); + #endif + + if (result) { + generar_error(mv, strerror(errno)); + return; + } + + latC_apilar(mv, latC_crear_logico(mv, true)); +} + +void lat_remover_dir(lat_mv *mv) { + bool recursivo; + + lat_objeto *obj1 = latC_desapilar(mv); + if (obj1->tipo == T_NULL) { + recursivo = false; + } else { + recursivo = latC_checar_logico(mv, obj1); + } + + lat_objeto *obj2 = latC_desapilar(mv); + char *ruta = latC_checar_cadena(mv, obj2); + + DIR *directorio = opendir(ruta); + struct stat comprobar; + + if (directorio) { + closedir(directorio); + + if (recursivo) { + remover_dir_recursivo(ruta); + } else { + rmdir(ruta); + } + + ultimo_error = strerror(errno); + + if (!stat(ruta, &comprobar)) { + generar_error(mv, ultimo_error); + return; + } + + latC_apilar(mv, latC_crear_logico(mv, true)); + } else { + generar_error(mv, strerror(errno)); + } +} + +void lat_listar_dir(lat_mv *mv) { + bool recursivo; + + lat_objeto *obj1 = latC_desapilar(mv); + if (obj1->tipo == T_NULL) { + recursivo = false; + } else { + recursivo = latC_checar_logico(mv, obj1); + } + + lat_objeto *obj2 = latC_desapilar(mv); + char *ruta = arreglar_ruta(latC_checar_cadena(mv, obj2)); + + lista *elementos = ( + recursivo ? listar_dir_recursivo(mv, ruta) : listar_dir(mv, ruta)); + + free(ruta); + + if (elementos) { + latC_apilar(mv, latC_crear_lista(mv, elementos)); + } else { + generar_error(mv, ultimo_error); + } +} + +void lat_existe(lat_mv *mv) { + lat_objeto *obj = latC_desapilar(mv); + char *ruta = latC_checar_cadena(mv, obj); + + struct stat ruta_stat; + latC_apilar(mv, latC_crear_logico(mv, !stat(ruta, &ruta_stat))); +} + +void lat_es_dir(lat_mv *mv) { + lat_objeto *obj = latC_desapilar(mv); + char *ruta = latC_checar_cadena(mv, obj); + + struct stat ruta_stat; + + if (stat(ruta, &ruta_stat)) { + generar_error(mv, strerror(errno)); + return; + } + + latC_apilar(mv, latC_crear_logico(mv, S_ISDIR(ruta_stat.st_mode))); +} + +void lat_es_archivo(lat_mv *mv) { + lat_objeto *obj = latC_desapilar(mv); + char *ruta = latC_checar_cadena(mv, obj); + + struct stat ruta_stat; + + if (stat(ruta, &ruta_stat)) { + generar_error(mv, strerror(errno)); + return; + } + + latC_apilar(mv, latC_crear_logico(mv, S_ISREG(ruta_stat.st_mode))); +} diff --git a/src/latino-libtipos.c b/src/latino-libtipos.c new file mode 100644 index 0000000..d1b78a7 --- /dev/null +++ b/src/latino-libtipos.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include + +int utf8_longitud(const char *cadena) { + int len = 0; + while (*cadena != '\0') { + if ((*cadena & 0xc0) != 0x80) { + len++; + } + cadena++; + } + return len; +} + +wchar_t *utf8_a_utf16(const char *cadena_utf8) { + int len = utf8_longitud(cadena_utf8); + + wchar_t *cadena_utf16 = (wchar_t*)malloc((len + 1) * sizeof(wchar_t)); + + int i = 0; + while (*cadena_utf8 != '\0') { + uint32_t codepoint; + int bytes; + + if ((*cadena_utf8 & 0x80) == 0) { + codepoint = *cadena_utf8 & 0x7f; + bytes = 1; + } else if ((*cadena_utf8 & 0xe0) == 0xc0) { + codepoint = *cadena_utf8 & 0x1f; + bytes = 2; + } else if ((*cadena_utf8 & 0xf0) == 0xe0) { + codepoint = *cadena_utf8 & 0x0f; + bytes = 3; + } else if ((*cadena_utf8 & 0xf8) == 0xf0) { + codepoint = *cadena_utf8 & 0x07; + bytes = 4; + } else { + free(cadena_utf16); + return NULL; + } + + for (int j = 1; j < bytes; j++) { + if ((cadena_utf8[j] & 0xc0) != 0x80) { + free(cadena_utf16); + return NULL; + } + codepoint = (codepoint << 6) | (cadena_utf8[j] & 0x3f); + } + cadena_utf8 += bytes; + + if (codepoint < 0x10000) { + cadena_utf16[i++] = (wchar_t)codepoint; + } else { + codepoint -= 0x10000; + cadena_utf16[i++] = (wchar_t)((codepoint >> 10) | 0xd800); + cadena_utf16[i++] = (wchar_t)((codepoint & 0x3ff) | 0xdc00); + } + } + + cadena_utf16[i] = L'\0'; + return cadena_utf16; +}