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;
+}