|
@@ -2,34 +2,6 @@
|
|
|
#ifndef LIB_H
|
|
#ifndef LIB_H
|
|
|
# define LIB_H
|
|
# define LIB_H
|
|
|
|
|
|
|
|
-# ifndef _STDINT_H
|
|
|
|
|
-# define LIB_H_STDINT
|
|
|
|
|
-
|
|
|
|
|
-# define intmax_t long int
|
|
|
|
|
-# endif /* _STDINT_H */
|
|
|
|
|
-
|
|
|
|
|
-# ifndef _UNISTD_H
|
|
|
|
|
-# define LIB_H_UNISTD
|
|
|
|
|
-
|
|
|
|
|
-# define R_OK 4
|
|
|
|
|
-# define W_OK 2
|
|
|
|
|
-# define X_OK 1
|
|
|
|
|
-# define F_OK 0
|
|
|
|
|
-# endif /* _UNISTD_H */
|
|
|
|
|
-
|
|
|
|
|
-# ifndef NULL
|
|
|
|
|
-# define LIB_H_NULL
|
|
|
|
|
-# define NULL ((void *) 0)
|
|
|
|
|
-# endif /* NULL */
|
|
|
|
|
-
|
|
|
|
|
-# ifndef _STDBOOL_H
|
|
|
|
|
-# define LIB_H_STDBOOL
|
|
|
|
|
-
|
|
|
|
|
-# define bool unsigned char
|
|
|
|
|
-# define true 1
|
|
|
|
|
-# define false 0
|
|
|
|
|
-# endif /* _STDBOOL_H */
|
|
|
|
|
-
|
|
|
|
|
/* --------------------------- START GLOBAL DEF ---------------------------- */
|
|
/* --------------------------- START GLOBAL DEF ---------------------------- */
|
|
|
|
|
|
|
|
# define ALLOC_FUNC void *(*alloc)(u64)
|
|
# define ALLOC_FUNC void *(*alloc)(u64)
|
|
@@ -51,30 +23,45 @@ enum err {
|
|
|
ERR_NOT_INT,
|
|
ERR_NOT_INT,
|
|
|
ERR_TOO_BIG,
|
|
ERR_TOO_BIG,
|
|
|
ERR_NULL_ARG,
|
|
ERR_NULL_ARG,
|
|
|
|
|
+ ERR_SIZE_ZERO,
|
|
|
ERR_INVALID_ARG,
|
|
ERR_INVALID_ARG,
|
|
|
|
|
+ ERR_INVALID_SIZE,
|
|
|
|
|
+ ERR_INVALID_PPM_FORMAT,
|
|
|
ERR_NOT_FOUND,
|
|
ERR_NOT_FOUND,
|
|
|
|
|
+ ERR_NO_MATCH,
|
|
|
|
|
+ ERR_AMBIGUOUS,
|
|
|
ERR_INDEX_TOO_LARGE,
|
|
ERR_INDEX_TOO_LARGE,
|
|
|
ERR_FAILED_OPEN,
|
|
ERR_FAILED_OPEN,
|
|
|
ERR_FAILED_CLOSE,
|
|
ERR_FAILED_CLOSE,
|
|
|
ERR_FAILED_READ,
|
|
ERR_FAILED_READ,
|
|
|
ERR_FAILED_WRITE,
|
|
ERR_FAILED_WRITE,
|
|
|
|
|
+ ERR_FAILED_PIPE,
|
|
|
|
|
+ ERR_FAILED_LSEEK,
|
|
|
ERR_FAILED_FORK,
|
|
ERR_FAILED_FORK,
|
|
|
ERR_FAILED_WAITPID,
|
|
ERR_FAILED_WAITPID,
|
|
|
ERR_FAILED_STAT,
|
|
ERR_FAILED_STAT,
|
|
|
ERR_FAILED_OPENDIR,
|
|
ERR_FAILED_OPENDIR,
|
|
|
ERR_FAILED_READDIR,
|
|
ERR_FAILED_READDIR,
|
|
|
|
|
+ ERR_FAILED_HASHING,
|
|
|
|
|
+ ERR_FAILED_ENCRYPTING,
|
|
|
|
|
+ ERR_FAILED_DECRYPTING,
|
|
|
ERR_WROTE_WRONG_AMOUNT,
|
|
ERR_WROTE_WRONG_AMOUNT,
|
|
|
ERR_FAILED_ALLOC,
|
|
ERR_FAILED_ALLOC,
|
|
|
ERR_FAILED_REALLOC,
|
|
ERR_FAILED_REALLOC,
|
|
|
ERR_MKDIR_FAILED,
|
|
ERR_MKDIR_FAILED,
|
|
|
- ERR_FAILED_HASHING,
|
|
|
|
|
ERR_STR_EMPTY,
|
|
ERR_STR_EMPTY,
|
|
|
|
|
+ ERR_FILE_EMPTY,
|
|
|
ERR_PATH_EMPTY,
|
|
ERR_PATH_EMPTY,
|
|
|
ERR_PATH_INVALID,
|
|
ERR_PATH_INVALID,
|
|
|
ERR_PATH_FILE_EMPTY,
|
|
ERR_PATH_FILE_EMPTY,
|
|
|
ERR_PATH_FILE_FAILED_SEEK,
|
|
ERR_PATH_FILE_FAILED_SEEK,
|
|
|
ERR_CMD_NON_ZERO_EXIT_CODE,
|
|
ERR_CMD_NON_ZERO_EXIT_CODE,
|
|
|
- ERR_SGFX_POS_OUTSIDE_CANVAS
|
|
|
|
|
|
|
+ ERR_SGFX_POS_OUTSIDE_CANVAS,
|
|
|
|
|
+ ERR_X11_FAILED_OPEN_DISPLAY,
|
|
|
|
|
+ ERR_X11_FAILED_CREATE_GC,
|
|
|
|
|
+ ERR_X11_FAILED_CREATE_IMAGE,
|
|
|
|
|
+ ERR_X11_FAILED_INIT_IMAGE,
|
|
|
|
|
+ ERR_X11_FAILED_GET_WIN_ATTR
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const char *err2cstr(enum err err);
|
|
const char *err2cstr(enum err err);
|
|
@@ -90,30 +77,45 @@ err2cstr(enum err err)
|
|
|
case ERR_NOT_INT: return "ERR_NOT_INT";
|
|
case ERR_NOT_INT: return "ERR_NOT_INT";
|
|
|
case ERR_TOO_BIG: return "ERR_TOO_BIG";
|
|
case ERR_TOO_BIG: return "ERR_TOO_BIG";
|
|
|
case ERR_NULL_ARG: return "ERR_NULL_ARG";
|
|
case ERR_NULL_ARG: return "ERR_NULL_ARG";
|
|
|
|
|
+ case ERR_SIZE_ZERO: return "ERR_SIZE_ZERO";
|
|
|
case ERR_INVALID_ARG: return "ERR_INVALID_ARG";
|
|
case ERR_INVALID_ARG: return "ERR_INVALID_ARG";
|
|
|
|
|
+ case ERR_INVALID_SIZE: return "ERR_INVALID_SIZE";
|
|
|
|
|
+ case ERR_INVALID_PPM_FORMAT: return "ERR_INVALID_PPM_FORMAT";
|
|
|
case ERR_NOT_FOUND: return "ERR_NOT_FOUND";
|
|
case ERR_NOT_FOUND: return "ERR_NOT_FOUND";
|
|
|
|
|
+ case ERR_NO_MATCH: return "ERR_NO_MATCH";
|
|
|
|
|
+ case ERR_AMBIGUOUS: return "ERR_AMBIGUOUS";
|
|
|
case ERR_INDEX_TOO_LARGE: return "ERR_INDEX_TOO_LARGE";
|
|
case ERR_INDEX_TOO_LARGE: return "ERR_INDEX_TOO_LARGE";
|
|
|
case ERR_FAILED_OPEN: return "ERR_FAILED_OPEN";
|
|
case ERR_FAILED_OPEN: return "ERR_FAILED_OPEN";
|
|
|
case ERR_FAILED_CLOSE: return "ERR_FAILED_CLOSE";
|
|
case ERR_FAILED_CLOSE: return "ERR_FAILED_CLOSE";
|
|
|
case ERR_FAILED_READ: return "ERR_FAILED_READ";
|
|
case ERR_FAILED_READ: return "ERR_FAILED_READ";
|
|
|
case ERR_FAILED_WRITE: return "ERR_FAILED_WRITE";
|
|
case ERR_FAILED_WRITE: return "ERR_FAILED_WRITE";
|
|
|
|
|
+ case ERR_FAILED_PIPE: return "ERR_FAILED_PIPE";
|
|
|
|
|
+ case ERR_FAILED_LSEEK: return "ERR_FAILED_LSEEK";
|
|
|
case ERR_FAILED_FORK: return "ERR_FAILED_FORK";
|
|
case ERR_FAILED_FORK: return "ERR_FAILED_FORK";
|
|
|
case ERR_FAILED_WAITPID: return "ERR_FAILED_WAITPID";
|
|
case ERR_FAILED_WAITPID: return "ERR_FAILED_WAITPID";
|
|
|
case ERR_FAILED_STAT: return "ERR_FAILED_STAT";
|
|
case ERR_FAILED_STAT: return "ERR_FAILED_STAT";
|
|
|
case ERR_FAILED_OPENDIR: return "ERR_FAILED_OPENDIR";
|
|
case ERR_FAILED_OPENDIR: return "ERR_FAILED_OPENDIR";
|
|
|
case ERR_FAILED_READDIR: return "ERR_FAILED_READDIR";
|
|
case ERR_FAILED_READDIR: return "ERR_FAILED_READDIR";
|
|
|
|
|
+ case ERR_FAILED_HASHING: return "ERR_FAILED_HASHING";
|
|
|
|
|
+ case ERR_FAILED_ENCRYPTING: return "ERR_FAILED_ENCRYPTING";
|
|
|
|
|
+ case ERR_FAILED_DECRYPTING: return "ERR_FAILED_DECRYPTING";
|
|
|
case ERR_WROTE_WRONG_AMOUNT: return "ERR_WROTE_WRONG_AMOUNT";
|
|
case ERR_WROTE_WRONG_AMOUNT: return "ERR_WROTE_WRONG_AMOUNT";
|
|
|
case ERR_FAILED_ALLOC: return "ERR_FAILED_ALLOC";
|
|
case ERR_FAILED_ALLOC: return "ERR_FAILED_ALLOC";
|
|
|
case ERR_FAILED_REALLOC: return "ERR_FAILED_REALLOC";
|
|
case ERR_FAILED_REALLOC: return "ERR_FAILED_REALLOC";
|
|
|
case ERR_MKDIR_FAILED: return "ERR_MKDIR_FAILED";
|
|
case ERR_MKDIR_FAILED: return "ERR_MKDIR_FAILED";
|
|
|
- case ERR_FAILED_HASHING: return "ERR_FAILED_HASHING";
|
|
|
|
|
case ERR_STR_EMPTY: return "ERR_STR_EMPTY";
|
|
case ERR_STR_EMPTY: return "ERR_STR_EMPTY";
|
|
|
|
|
+ case ERR_FILE_EMPTY: return "ERR_FILE_EMPTY";
|
|
|
case ERR_PATH_EMPTY: return "ERR_PATH_EMPTY";
|
|
case ERR_PATH_EMPTY: return "ERR_PATH_EMPTY";
|
|
|
case ERR_PATH_INVALID: return "ERR_PATH_INVALID";
|
|
case ERR_PATH_INVALID: return "ERR_PATH_INVALID";
|
|
|
case ERR_PATH_FILE_EMPTY: return "ERR_PATH_FILE_EMPTY";
|
|
case ERR_PATH_FILE_EMPTY: return "ERR_PATH_FILE_EMPTY";
|
|
|
case ERR_PATH_FILE_FAILED_SEEK: return "ERR_PATH_FILE_FAILED_SEEK";
|
|
case ERR_PATH_FILE_FAILED_SEEK: return "ERR_PATH_FILE_FAILED_SEEK";
|
|
|
case ERR_CMD_NON_ZERO_EXIT_CODE: return "ERR_CMD_NON_ZERO_EXIT_CODE";
|
|
case ERR_CMD_NON_ZERO_EXIT_CODE: return "ERR_CMD_NON_ZERO_EXIT_CODE";
|
|
|
case ERR_SGFX_POS_OUTSIDE_CANVAS: return "ERR_SGFX_POS_OUTSIDE_CANVAS";
|
|
case ERR_SGFX_POS_OUTSIDE_CANVAS: return "ERR_SGFX_POS_OUTSIDE_CANVAS";
|
|
|
|
|
+ case ERR_X11_FAILED_OPEN_DISPLAY: return "ERR_X11_FAILED_OPEN_DISPLAY";
|
|
|
|
|
+ case ERR_X11_FAILED_CREATE_GC: return "ERR_X11_FAILED_CREATE_GC";
|
|
|
|
|
+ case ERR_X11_FAILED_CREATE_IMAGE: return "ERR_X11_FAILED_CREATE_IMAGE";
|
|
|
|
|
+ case ERR_X11_FAILED_INIT_IMAGE: return "ERR_X11_FAILED_INIT_IMAGE";
|
|
|
|
|
+ case ERR_X11_FAILED_GET_WIN_ATTR: return "ERR_X11_FAILED_GET_WIN_ATTR";
|
|
|
default: return "UNKNOWN_ERR";
|
|
default: return "UNKNOWN_ERR";
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -138,12 +140,29 @@ typedef unsigned char u8;
|
|
|
|
|
|
|
|
/* ------------------------------ END INT DEF ------------------------------ */
|
|
/* ------------------------------ END INT DEF ------------------------------ */
|
|
|
|
|
|
|
|
|
|
+# ifndef LIB_DO_NOT_INCLUDE_IT
|
|
|
|
|
+#include <fcntl.h>
|
|
|
|
|
+#include <stdio.h>
|
|
|
|
|
+#include <errno.h>
|
|
|
|
|
+#include <stdlib.h>
|
|
|
|
|
+#include <stdint.h>
|
|
|
|
|
+#include <stdarg.h>
|
|
|
|
|
+#include <unistd.h>
|
|
|
|
|
+#include <dirent.h>
|
|
|
|
|
+#include <stdbool.h>
|
|
|
|
|
+#include <sys/wait.h>
|
|
|
|
|
+#include <sys/stat.h>
|
|
|
|
|
+# endif /* LIB_DO_NOT_INCLUDE_IT */
|
|
|
|
|
+
|
|
|
|
|
+# define _r_ __restrict__
|
|
|
|
|
+
|
|
|
extern char **environ;
|
|
extern char **environ;
|
|
|
|
|
|
|
|
void *malloc(u64 size);
|
|
void *malloc(u64 size);
|
|
|
void *realloc(void *ptr, u64 new_size);
|
|
void *realloc(void *ptr, u64 new_size);
|
|
|
void free(void *ptr);
|
|
void free(void *ptr);
|
|
|
-void *memcpy(void *dest, const void *src, u64 n);
|
|
|
|
|
|
|
+void *memcpy(void *_r_ dest, const void *_r_ src, u64 n);
|
|
|
|
|
+void *memmove(void *dest, const void *src, u64 n);
|
|
|
void *memset(void *s, int c, u64 n);
|
|
void *memset(void *s, int c, u64 n);
|
|
|
char *getenv(const char *name);
|
|
char *getenv(const char *name);
|
|
|
void abort(void);
|
|
void abort(void);
|
|
@@ -154,21 +173,6 @@ int execve(const char *path, char *const argv[], char *const envp[]);
|
|
|
int execvpe(const char *path, char *const argv[], char *const envp[]);
|
|
int execvpe(const char *path, char *const argv[], char *const envp[]);
|
|
|
|
|
|
|
|
int fork(void);
|
|
int fork(void);
|
|
|
-# ifndef WIFEXITED
|
|
|
|
|
-# error "Must import <sys/wait.h> before lib.h!"
|
|
|
|
|
-# endif
|
|
|
|
|
-
|
|
|
|
|
-# if (! defined(_STDARG_H)) || (! defined(va_start))
|
|
|
|
|
-# error "Must import <stdarg.h> before lib.h!"
|
|
|
|
|
-# endif
|
|
|
|
|
-
|
|
|
|
|
-# ifndef _DIRENT_H
|
|
|
|
|
-# error "Must import <dirent.h> before lib.h!"
|
|
|
|
|
-# endif
|
|
|
|
|
-
|
|
|
|
|
-# ifndef _ERRNO_H
|
|
|
|
|
-# error "Must import <errno.h> before lib.h!"
|
|
|
|
|
-# endif
|
|
|
|
|
|
|
|
|
|
/* ----------------------------- START LIB DEF ----------------------------- */
|
|
/* ----------------------------- START LIB DEF ----------------------------- */
|
|
|
|
|
|
|
@@ -227,27 +231,133 @@ int fork(void);
|
|
|
return ret_val; \
|
|
return ret_val; \
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-# define _r_ __restrict__
|
|
|
|
|
-
|
|
|
|
|
# define SIZEOF_MEMBER(Struct, Member) sizeof(((Struct *)0)->Member)
|
|
# define SIZEOF_MEMBER(Struct, Member) sizeof(((Struct *)0)->Member)
|
|
|
|
|
|
|
|
# define CAST(Type, Var) ((Type) (Var))
|
|
# define CAST(Type, Var) ((Type) (Var))
|
|
|
|
|
|
|
|
-/*# define LIB_FREE lib_free*/
|
|
|
|
|
|
|
+# define LIB_CLOSE close
|
|
|
|
|
+# define LIB_LSEEK lseek
|
|
|
|
|
+# define LIB_READ read
|
|
|
|
|
+# define LIB_MALLOC malloc
|
|
|
|
|
+# define LIB_CALLOC calloc
|
|
|
|
|
+# define LIB_MEMCPY memcpy
|
|
|
|
|
+# define LIB_OPEN open
|
|
|
# define LIB_FREE(Ptr) if ( (Ptr) != NULL ) { free((void *) (Ptr)); }
|
|
# define LIB_FREE(Ptr) if ( (Ptr) != NULL ) { free((void *) (Ptr)); }
|
|
|
|
|
|
|
|
-void lib_free(const void *ptr);
|
|
|
|
|
const char *temp_sprintf(const char *fmt, ...);
|
|
const char *temp_sprintf(const char *fmt, ...);
|
|
|
|
|
|
|
|
-# if defined(IMP) || defined(IMP_LIB)
|
|
|
|
|
|
|
+#define COALESCE(...) \
|
|
|
|
|
+ _COALESCE_NARG_(__VA_ARGS__, \
|
|
|
|
|
+ COALESCE5, COALESCE4, \
|
|
|
|
|
+ COALESCE3, COALESCE2)(__VA_ARGS__)
|
|
|
|
|
+
|
|
|
|
|
+// Helper macros for different numbers of arguments
|
|
|
|
|
+#define _COALESCE_NARG_(...) _COALESCE_NARG_I_(__VA_ARGS__)
|
|
|
|
|
+#define _COALESCE_NARG_I_(a1, a2, a3, a4, a5, N, ...) N
|
|
|
|
|
+#define COALESCE5(a, b, c, d, e) COALESCE2(COALESCE4(a, b, c, d), e)
|
|
|
|
|
+#define COALESCE4(a, b, c, d) COALESCE2(COALESCE3(a, b, c), d)
|
|
|
|
|
+#define COALESCE3(a, b, c) COALESCE2(COALESCE2(a, b), c)
|
|
|
|
|
+#define COALESCE2(a, b) (((a) != NULL) ? (a) : (b))
|
|
|
|
|
+
|
|
|
|
|
+struct __file_slurp_args {
|
|
|
|
|
+ u64 path_size;
|
|
|
|
|
+ u64 *out_size;
|
|
|
|
|
+ enum err *out_err;
|
|
|
|
|
+};
|
|
|
|
|
+#define file_slurp(Path, ...) \
|
|
|
|
|
+ _file_slurp( \
|
|
|
|
|
+ (Path), \
|
|
|
|
|
+ (struct __file_slurp_args) { \
|
|
|
|
|
+ .path_size=0, \
|
|
|
|
|
+ .out_size=NULL, \
|
|
|
|
|
+ .out_err=NULL, \
|
|
|
|
|
+ __VA_ARGS__ \
|
|
|
|
|
+ } \
|
|
|
|
|
+ )
|
|
|
|
|
+u8 *_file_slurp(const char *path, struct __file_slurp_args args);
|
|
|
|
|
+
|
|
|
|
|
+struct __file_spit_args {
|
|
|
|
|
+ bool append;
|
|
|
|
|
+ bool create;
|
|
|
|
|
+ u16 mode;
|
|
|
|
|
+ u64 path_size;
|
|
|
|
|
+ enum err *out_err;
|
|
|
|
|
+};
|
|
|
|
|
+#define file_spit(Path, Data, Size, ...) \
|
|
|
|
|
+ _file_spit( \
|
|
|
|
|
+ (Path), \
|
|
|
|
|
+ (Data), \
|
|
|
|
|
+ (Size), \
|
|
|
|
|
+ (struct __file_spit_args) { \
|
|
|
|
|
+ .append=false, \
|
|
|
|
|
+ .create=true, \
|
|
|
|
|
+ .mode=00644, \
|
|
|
|
|
+ .path_size=0, \
|
|
|
|
|
+ .out_err=NULL, \
|
|
|
|
|
+ __VA_ARGS__ \
|
|
|
|
|
+ } \
|
|
|
|
|
+ )
|
|
|
|
|
+enum err _file_spit(const char *_r_ path, u8 *_r_ data, u64 size,
|
|
|
|
|
+ struct __file_spit_args args);
|
|
|
|
|
|
|
|
-void
|
|
|
|
|
-lib_free(const void *ptr)
|
|
|
|
|
-{
|
|
|
|
|
- if ( ptr == NULL ) return;
|
|
|
|
|
|
|
+struct __cstr_from_i64_args {
|
|
|
|
|
+ bool alloc;
|
|
|
|
|
+ u64 *out_size;
|
|
|
|
|
+ enum err *out_err;
|
|
|
|
|
+};
|
|
|
|
|
+#define cstr_from_i64(Num, ...) \
|
|
|
|
|
+ _cstr_from_i64( \
|
|
|
|
|
+ (Num), \
|
|
|
|
|
+ (struct __cstr_from_i64_args) { \
|
|
|
|
|
+ .alloc=false, \
|
|
|
|
|
+ .out_size=NULL, \
|
|
|
|
|
+ .out_err=NULL, \
|
|
|
|
|
+ __VA_ARGS__ \
|
|
|
|
|
+ } \
|
|
|
|
|
+ )
|
|
|
|
|
+char *_cstr_from_i64(i64 num, struct __cstr_from_i64_args args);
|
|
|
|
|
|
|
|
- free((void *)ptr);
|
|
|
|
|
-}
|
|
|
|
|
|
|
+struct rgb_pixel { u8 r, g, b; };
|
|
|
|
|
+struct rgb_pixel_array { struct rgb_pixel *data; u64 size; };
|
|
|
|
|
+struct rgb_pixel_da { struct rgb_pixel *data; u64 size; u64 cap; };
|
|
|
|
|
+
|
|
|
|
|
+struct ppm {
|
|
|
|
|
+ struct rgb_pixel *data;
|
|
|
|
|
+ u64 width;
|
|
|
|
|
+ u64 height;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+struct __ppm_from_bytes_args {
|
|
|
|
|
+ enum err *out_err;
|
|
|
|
|
+};
|
|
|
|
|
+#define ppm_from_bytes(Data, Size, ...) \
|
|
|
|
|
+ _ppm_from_bytes( \
|
|
|
|
|
+ (Data), \
|
|
|
|
|
+ (Size), \
|
|
|
|
|
+ (struct __ppm_from_bytes_args) { \
|
|
|
|
|
+ .out_err=NULL, \
|
|
|
|
|
+ __VA_ARGS__ \
|
|
|
|
|
+ } \
|
|
|
|
|
+ )
|
|
|
|
|
+struct ppm _ppm_from_bytes(const u8 *_r_ data, u64 size,
|
|
|
|
|
+ struct __ppm_from_bytes_args args);
|
|
|
|
|
+
|
|
|
|
|
+struct __ppm_to_bytes_args {
|
|
|
|
|
+ u64 *out_size;
|
|
|
|
|
+ enum err *out_err;
|
|
|
|
|
+};
|
|
|
|
|
+#define ppm_to_bytes(PPM, ...) \
|
|
|
|
|
+ _ppm_to_bytes( \
|
|
|
|
|
+ (PPM), \
|
|
|
|
|
+ (struct __ppm_to_bytes_args) { \
|
|
|
|
|
+ .out_size=NULL, \
|
|
|
|
|
+ .out_err=NULL, \
|
|
|
|
|
+ __VA_ARGS__ \
|
|
|
|
|
+ } \
|
|
|
|
|
+ )
|
|
|
|
|
+u8 *_ppm_to_bytes(struct ppm *_r_ ppm, struct __ppm_to_bytes_args args);
|
|
|
|
|
+
|
|
|
|
|
+# if defined(IMP) || defined(IMP_LIB)
|
|
|
|
|
|
|
|
const char *
|
|
const char *
|
|
|
temp_sprintf(const char *fmt, ...)
|
|
temp_sprintf(const char *fmt, ...)
|
|
@@ -265,6 +375,330 @@ temp_sprintf(const char *fmt, ...)
|
|
|
return (const char *) buf;
|
|
return (const char *) buf;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+u8 *
|
|
|
|
|
+_file_slurp(const char *path, struct __file_slurp_args args)
|
|
|
|
|
+{
|
|
|
|
|
+ enum err err = ERR_OK;
|
|
|
|
|
+ enum err *perr = &err;
|
|
|
|
|
+
|
|
|
|
|
+ i32 fd = -1;
|
|
|
|
|
+ u8 *data = NULL;
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.out_err != NULL ) { perr = args.out_err; }
|
|
|
|
|
+ if ( *perr != ERR_OK ) { goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ if ( path == NULL ) { *perr = ERR_NULL_ARG; goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ char *_path = (char *) path;
|
|
|
|
|
+ if ( args.path_size != 0 ) {
|
|
|
|
|
+ _path = calloc(args.path_size+1, sizeof(*_path));
|
|
|
|
|
+ if ( _path == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+ memcpy(_path, path, args.path_size);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fd = open(_path, O_RDONLY);
|
|
|
|
|
+ if ( fd < 0 ) { *perr = ERR_FAILED_OPEN; goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ i64 file_size = lseek(fd, 0, SEEK_END);
|
|
|
|
|
+ if ( file_size < 0 ) { *perr = ERR_PATH_FILE_FAILED_SEEK; goto exit_err; }
|
|
|
|
|
+ if ( file_size == 0 ) { *perr = ERR_PATH_FILE_EMPTY; goto exit_err; }
|
|
|
|
|
+ {
|
|
|
|
|
+ i64 ss = lseek(fd, 0, SEEK_SET);
|
|
|
|
|
+ if ( ss < 0 ) { *perr = ERR_PATH_FILE_FAILED_SEEK; goto exit_err; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ data = calloc((u64)file_size + 1, sizeof(*data));
|
|
|
|
|
+ if ( data == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ {
|
|
|
|
|
+ i64 rd = read(fd, data, (u64) file_size);
|
|
|
|
|
+ if ( rd < 0 ) { *perr = ERR_FAILED_READ; goto exit_err; }
|
|
|
|
|
+ if ( rd == 0 ) { *perr = ERR_PATH_FILE_EMPTY; goto exit_err; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( close(fd) != 0 ) {
|
|
|
|
|
+ /* It should be possible to handle EIO */
|
|
|
|
|
+ *perr = ERR_FAILED_CLOSE;
|
|
|
|
|
+ goto exit_err;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.out_size != NULL ) { *args.out_size = (u64) file_size; }
|
|
|
|
|
+
|
|
|
|
|
+ *perr = ERR_OK;
|
|
|
|
|
+ return data;
|
|
|
|
|
+exit_err:
|
|
|
|
|
+ if ( fd > 0 ) { close(fd); }
|
|
|
|
|
+ if ( data != NULL ) { free(data); }
|
|
|
|
|
+ if ( *perr == ERR_OK ) { *perr = ERR_GENERAL_ERROR; }
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+enum err _file_spit(const char *_r_ path, u8 *_r_ data, u64 size,
|
|
|
|
|
+ struct __file_spit_args args)
|
|
|
|
|
+{
|
|
|
|
|
+ enum err err = ERR_OK;
|
|
|
|
|
+ enum err *perr = &err;
|
|
|
|
|
+
|
|
|
|
|
+ i32 fd = -1;
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.out_err != NULL ) { perr = args.out_err; }
|
|
|
|
|
+ if ( *perr != ERR_OK ) { goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ if ( path == NULL ) { *perr = ERR_NULL_ARG; goto exit_err; }
|
|
|
|
|
+ if ( data == NULL ) { *perr = ERR_NULL_ARG; goto exit_err; }
|
|
|
|
|
+ if ( size == 0 ) { *perr = ERR_SIZE_ZERO; goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ char *_path = (char *) path;
|
|
|
|
|
+ if ( args.path_size != 0 ) {
|
|
|
|
|
+ _path = calloc(args.path_size+1, sizeof(*_path));
|
|
|
|
|
+ if ( _path == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+ memcpy(_path, path, args.path_size);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ {
|
|
|
|
|
+ i32 flags = O_WRONLY;
|
|
|
|
|
+ flags |= (args.append) * O_APPEND;
|
|
|
|
|
+ flags |= (args.create) * O_CREAT;
|
|
|
|
|
+ fd = open(_path, flags, args.mode);
|
|
|
|
|
+ if ( fd < 0 ) { *perr = ERR_FAILED_OPEN; goto exit_err; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ {
|
|
|
|
|
+ i64 wr = write(fd, data, size);
|
|
|
|
|
+ if ( wr < 0 ) { *perr = ERR_FAILED_WRITE; goto exit_err; }
|
|
|
|
|
+ if ( ((u64)wr) != size ) { *perr = ERR_FAILED_WRITE; goto exit_err; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( close(fd) != 0 ) {
|
|
|
|
|
+ /* It should be possible to handle EIO */
|
|
|
|
|
+ *perr = ERR_FAILED_CLOSE;
|
|
|
|
|
+ goto exit_err;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ *perr = ERR_OK;
|
|
|
|
|
+ return *perr;
|
|
|
|
|
+exit_err:
|
|
|
|
|
+ if ( fd > 0 ) { close(fd); }
|
|
|
|
|
+ if ( *perr == ERR_OK ) { *perr = ERR_GENERAL_ERROR; }
|
|
|
|
|
+ return *perr;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+char *
|
|
|
|
|
+_cstr_from_i64(i64 num, struct __cstr_from_i64_args args)
|
|
|
|
|
+{
|
|
|
|
|
+ static char data[32];
|
|
|
|
|
+ static u64 cap = 32;
|
|
|
|
|
+ u64 size = 0;
|
|
|
|
|
+
|
|
|
|
|
+ enum err err = ERR_OK;
|
|
|
|
|
+ enum err *perr = &err;
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.out_err != NULL ) { perr = args.out_err; }
|
|
|
|
|
+ if ( *perr != ERR_OK ) { goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ if ( num < 0 ) {
|
|
|
|
|
+ data[size++] = '-';
|
|
|
|
|
+ num *= -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ u64 _num = (u64)num;
|
|
|
|
|
+
|
|
|
|
|
+ while ( _num > 0 ) {
|
|
|
|
|
+ u8 mod = (u8) (_num % 10);
|
|
|
|
|
+ _num /= 10;
|
|
|
|
|
+ data[size++] = (char) (mod + '0');
|
|
|
|
|
+ if ( size >= cap ) { *perr = ERR_TOO_BIG; goto exit_err; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ u64 limit = (u64) size / 2;
|
|
|
|
|
+ for ( u64 i = 0; i < limit; ++i ) {
|
|
|
|
|
+ char t = data[i];
|
|
|
|
|
+ u64 other = (size-1)-i;
|
|
|
|
|
+ data[i] = data[other];
|
|
|
|
|
+ data[other] = t;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ data[size] = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.out_size != NULL ) { *args.out_size = size; }
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.alloc ) {
|
|
|
|
|
+ char *ret = NULL;
|
|
|
|
|
+ ret = calloc(size+1, sizeof(*ret));
|
|
|
|
|
+ if ( ret == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+ memcpy(ret, data, size);
|
|
|
|
|
+ return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return data;
|
|
|
|
|
+exit_err:
|
|
|
|
|
+ if ( *perr != ERR_OK ) { *perr = ERR_GENERAL_ERROR; }
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+struct ppm
|
|
|
|
|
+_ppm_from_bytes(const u8 *_r_ data, u64 size,
|
|
|
|
|
+ struct __ppm_from_bytes_args args)
|
|
|
|
|
+{
|
|
|
|
|
+ enum err err = ERR_OK;
|
|
|
|
|
+ enum err *perr = &err;
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.out_err != NULL ) { perr = args.out_err; }
|
|
|
|
|
+ if ( *perr != ERR_OK ) { goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ if ( data == NULL ) { *perr = ERR_NULL_ARG; goto exit_err; }
|
|
|
|
|
+ if ( size == 0 ) { *perr = ERR_SIZE_ZERO; goto exit_err; }
|
|
|
|
|
+ if ( size < 12 ) { *perr = ERR_INVALID_SIZE; goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ if ( *data++ != 'P' || *data++ != '6' || *data++ != '\n' ) {
|
|
|
|
|
+ *perr = ERR_INVALID_PPM_FORMAT; goto exit_err;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ u64 height = 0;
|
|
|
|
|
+ u64 width = 0;
|
|
|
|
|
+
|
|
|
|
|
+ {
|
|
|
|
|
+ u64 i = 0;
|
|
|
|
|
+ while ( *data != ' ' ) {
|
|
|
|
|
+ if ( *data < '0' || *data > '9' || i > 6 ) {
|
|
|
|
|
+ *perr = ERR_INVALID_PPM_FORMAT; goto exit_err;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ width = ((u64) (*data++ - '0')) + (width * 10);
|
|
|
|
|
+ ++i;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ data++;
|
|
|
|
|
+
|
|
|
|
|
+ i = 0;
|
|
|
|
|
+ while ( *data != '\n' ) {
|
|
|
|
|
+ if ( *data < '0' || *data > '9' || i > 6 ) {
|
|
|
|
|
+ *perr = ERR_INVALID_PPM_FORMAT; goto exit_err;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ height = ((u64) (*data++ - '0')) + (height * 10);
|
|
|
|
|
+ ++i;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ data++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( *data++ != '2' || *data++ != '5' || *data++ != '5' || *data++ != '\n' ) {
|
|
|
|
|
+ *perr = ERR_INVALID_PPM_FORMAT; goto exit_err;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ struct rgb_pixel_da da = {0};
|
|
|
|
|
+ da.size = 0;
|
|
|
|
|
+ da.cap = (height * width) + 1;
|
|
|
|
|
+ da.data = calloc(da.cap, sizeof(*da.data));
|
|
|
|
|
+ if ( da.data == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ struct rgb_pixel *reint = (struct rgb_pixel *) data;
|
|
|
|
|
+ for ( u64 i = 0; i < da.cap; ++i ) {
|
|
|
|
|
+ da.data[da.size++] = reint[i];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ struct ppm ret = {
|
|
|
|
|
+ .data=da.data,
|
|
|
|
|
+ .width=width,
|
|
|
|
|
+ .height=height
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ return ret;
|
|
|
|
|
+exit_err:
|
|
|
|
|
+ if ( *perr == ERR_OK ) { *perr = ERR_GENERAL_ERROR; }
|
|
|
|
|
+ return (struct ppm){0};
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+u8 *
|
|
|
|
|
+_ppm_to_bytes(struct ppm *_r_ ppm, struct __ppm_to_bytes_args args)
|
|
|
|
|
+{
|
|
|
|
|
+ enum err err = ERR_OK;
|
|
|
|
|
+ enum err *perr = &err;
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.out_err != NULL ) { perr = args.out_err; }
|
|
|
|
|
+ if ( *perr != ERR_OK ) { goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ if ( ppm == NULL ) { *perr = ERR_NULL_ARG; goto exit_err; }
|
|
|
|
|
+ if ( ppm->data == NULL ) { *perr = ERR_NULL_ARG; goto exit_err; }
|
|
|
|
|
+ if ( ppm->width == 0 || ppm->height == 0 ) {
|
|
|
|
|
+ *perr = ERR_SIZE_ZERO; goto exit_err;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ u8 *data = NULL;
|
|
|
|
|
+ u64 size = 0;
|
|
|
|
|
+ u64 cap = 32;
|
|
|
|
|
+
|
|
|
|
|
+ data = calloc(cap, sizeof(*data));
|
|
|
|
|
+ if ( data == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+
|
|
|
|
|
+ data[size++] = 'P';
|
|
|
|
|
+ data[size++] = '6';
|
|
|
|
|
+ data[size++] = '\n';
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ {
|
|
|
|
|
+ u64 width_size = 0;
|
|
|
|
|
+ char *width = cstr_from_i64((i64)ppm->width, .out_size=&width_size);
|
|
|
|
|
+ for ( u64 i = 0; i < width_size; ++i ) {
|
|
|
|
|
+ data[size++] = (u8)width[i];
|
|
|
|
|
+ if ( size >= cap ) {
|
|
|
|
|
+ cap *= 2;
|
|
|
|
|
+ data = realloc(data, cap);
|
|
|
|
|
+ if ( data == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ data[size++] = ' ';
|
|
|
|
|
+ if ( size >= cap ) {
|
|
|
|
|
+ cap *= 2;
|
|
|
|
|
+ data = realloc(data, cap);
|
|
|
|
|
+ if ( data == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ u64 height_size = 0;
|
|
|
|
|
+ char *height = cstr_from_i64((i64)ppm->height, .out_size=&height_size);
|
|
|
|
|
+ for ( u64 i = 0; i < height_size; ++i ) {
|
|
|
|
|
+ data[size++] = (u8)height[i];
|
|
|
|
|
+ if ( size >= cap ) {
|
|
|
|
|
+ cap *= 2;
|
|
|
|
|
+ data = realloc(data, cap);
|
|
|
|
|
+ if ( data == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( size+6 >= cap ) {
|
|
|
|
|
+ cap *= 2;
|
|
|
|
|
+ data = realloc(data, cap);
|
|
|
|
|
+ if ( data == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+ }
|
|
|
|
|
+ data[size++] = '\n';
|
|
|
|
|
+ data[size++] = '2';
|
|
|
|
|
+ data[size++] = '5';
|
|
|
|
|
+ data[size++] = '5';
|
|
|
|
|
+ data[size++] = '\n';
|
|
|
|
|
+
|
|
|
|
|
+ u64 end = ppm->width * ppm->height;
|
|
|
|
|
+ for ( u64 i = 0; i < end; ++i ) {
|
|
|
|
|
+ if ( size+4 >= cap ) {
|
|
|
|
|
+ cap *= 2;
|
|
|
|
|
+ data = realloc(data, cap);
|
|
|
|
|
+ if ( data == NULL ) { *perr = ERR_FAILED_ALLOC; goto exit_err; }
|
|
|
|
|
+ }
|
|
|
|
|
+ data[size++] = ppm->data[i].r;
|
|
|
|
|
+ data[size++] = ppm->data[i].g;
|
|
|
|
|
+ data[size++] = ppm->data[i].b;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.out_size != NULL ) { *args.out_size = size; }
|
|
|
|
|
+
|
|
|
|
|
+ return data;
|
|
|
|
|
+exit_err:
|
|
|
|
|
+ if ( data == NULL ) { free(data); }
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
# endif /* defined(IMP) || defined(IMP_LIB) */
|
|
# endif /* defined(IMP) || defined(IMP_LIB) */
|
|
|
|
|
|
|
|
/* ------------------------------ END LIB DEF ------------------------------ */
|
|
/* ------------------------------ END LIB DEF ------------------------------ */
|
|
@@ -337,6 +771,17 @@ const char *cstr_dup(const char *cstr, enum err *out_err);
|
|
|
bool cstr_eq(const char *_r_ cstr1, u64 size1,
|
|
bool cstr_eq(const char *_r_ cstr1, u64 size1,
|
|
|
const char *_r_ cstr2, u64 size2, enum err *_r_ out_err);
|
|
const char *_r_ cstr2, u64 size2, enum err *_r_ out_err);
|
|
|
|
|
|
|
|
|
|
+struct __cstr_has {
|
|
|
|
|
+ char *prefix;
|
|
|
|
|
+ u64 prefix_size;
|
|
|
|
|
+ char *suffix;
|
|
|
|
|
+ u64 suffix_size;
|
|
|
|
|
+ char c;
|
|
|
|
|
+ char *cstr;
|
|
|
|
|
+ u64 cstr_size;
|
|
|
|
|
+};
|
|
|
|
|
+bool _cstr_has(const char *_r_ cstr, u64 size, enum err *_r_ out_err);
|
|
|
|
|
+
|
|
|
bool cstr_endswith(const char *_r_ cstr, u64 size,
|
|
bool cstr_endswith(const char *_r_ cstr, u64 size,
|
|
|
const char *_r_ end, u64 end_size, enum err *_r_ out_err);
|
|
const char *_r_ end, u64 end_size, enum err *_r_ out_err);
|
|
|
|
|
|
|
@@ -433,7 +878,11 @@ cstr_eq(const char *_r_ cstr1, u64 size1,
|
|
|
LIB_ARG_MUST_NOT_BE_NULL(cstr1, out_err, false);
|
|
LIB_ARG_MUST_NOT_BE_NULL(cstr1, out_err, false);
|
|
|
LIB_ARG_MUST_NOT_BE_NULL(cstr2, out_err, false);
|
|
LIB_ARG_MUST_NOT_BE_NULL(cstr2, out_err, false);
|
|
|
|
|
|
|
|
|
|
+ if ( size1 == 0 ) { size1 = cstr_len(cstr1, NULL); }
|
|
|
|
|
+ if ( size2 == 0 ) { size2 = cstr_len(cstr2, NULL); }
|
|
|
|
|
+
|
|
|
if ( size1 != size2 ) return false;
|
|
if ( size1 != size2 ) return false;
|
|
|
|
|
+ if ( cstr1 == cstr2 ) return true;
|
|
|
|
|
|
|
|
for ( u64 i = 0; i < size1; ++i ) {
|
|
for ( u64 i = 0; i < size1; ++i ) {
|
|
|
if ( cstr1[i] != cstr2[i] ) return false;
|
|
if ( cstr1[i] != cstr2[i] ) return false;
|
|
@@ -802,6 +1251,25 @@ dyn_arr_destroy(struct dyn_arr *da, enum err *out_err)
|
|
|
LIB_SET_IF_NOT_NULL((OutErr), ERR_OK); \
|
|
LIB_SET_IF_NOT_NULL((OutErr), ERR_OK); \
|
|
|
} while(0)
|
|
} while(0)
|
|
|
|
|
|
|
|
|
|
+# define DA_RESERVE(Da, Amount, OutErr) \
|
|
|
|
|
+ do { \
|
|
|
|
|
+ if ( (OutErr) != NULL ) { \
|
|
|
|
|
+ if ( *(OutErr) != ERR_OK ) { \
|
|
|
|
|
+ break; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ } \
|
|
|
|
|
+ if ( ((Da).cap - (Da).size) >= (Amount) ) { break; } \
|
|
|
|
|
+ (Da).cap = (Da).cap + (Amount); \
|
|
|
|
|
+ (Da).data = realloc((Da).data, sizeof(*(Da).data) * (Da).cap); \
|
|
|
|
|
+ if ( (Da).data == NULL ) { \
|
|
|
|
|
+ LIB_SET_IF_NOT_NULL((OutErr), ERR_FAILED_REALLOC); \
|
|
|
|
|
+ break; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ memset((Da).data + (Da).size, 0, \
|
|
|
|
|
+ sizeof(*(Da).data) * ((Da).cap - (Da).size)); \
|
|
|
|
|
+ LIB_SET_IF_NOT_NULL((OutErr), ERR_OK); \
|
|
|
|
|
+ } while(0)
|
|
|
|
|
+
|
|
|
# define DA_APPEND_DATA(Da, Val, ItemNum, ErrVar) \
|
|
# define DA_APPEND_DATA(Da, Val, ItemNum, ErrVar) \
|
|
|
do { \
|
|
do { \
|
|
|
if ( (ErrVar) != NULL ) { \
|
|
if ( (ErrVar) != NULL ) { \
|
|
@@ -834,6 +1302,23 @@ dyn_arr_destroy(struct dyn_arr *da, enum err *out_err)
|
|
|
LIB_SET_IF_NOT_NULL((ErrVar), ERR_OK); \
|
|
LIB_SET_IF_NOT_NULL((ErrVar), ERR_OK); \
|
|
|
} while(0)
|
|
} while(0)
|
|
|
|
|
|
|
|
|
|
+# define DA_DELETE(Da, Index, ErrVar) \
|
|
|
|
|
+ do { \
|
|
|
|
|
+ if ( (ErrVar) != NULL ) { \
|
|
|
|
|
+ if ( *(ErrVar) != ERR_OK ) { \
|
|
|
|
|
+ break; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ } \
|
|
|
|
|
+ if ( (Index) >= (Da).size ) { \
|
|
|
|
|
+ LIB_SET_IF_NOT_NULL((ErrVar), ERR_INDEX_TOO_LARGE); \
|
|
|
|
|
+ break; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ --(Da).size; \
|
|
|
|
|
+ memmove((Da).data + (Index), ((Da).data+(Index))+1, \
|
|
|
|
|
+ sizeof(*(Da).data)*((Da).size - ((Index)+1))); \
|
|
|
|
|
+ memset((Da).data + (Da).size, 0, sizeof(*(Da).data)); \
|
|
|
|
|
+ } while(0)
|
|
|
|
|
+
|
|
|
# define DAV_APPEND(Da, Val, ValSize, ErrVar) \
|
|
# define DAV_APPEND(Da, Val, ValSize, ErrVar) \
|
|
|
do { \
|
|
do { \
|
|
|
if ( ErrVar != NULL ) { \
|
|
if ( ErrVar != NULL ) { \
|
|
@@ -1740,14 +2225,14 @@ struct tokenizer {
|
|
|
|
|
|
|
|
struct token last;
|
|
struct token last;
|
|
|
|
|
|
|
|
- struct path src;
|
|
|
|
|
|
|
+ struct str src;
|
|
|
struct str code;
|
|
struct str code;
|
|
|
|
|
|
|
|
void *edata; /* This is not used by the lib */
|
|
void *edata; /* This is not used by the lib */
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
-struct tokenizer tokenizer_create(struct str code, struct path src,
|
|
|
|
|
|
|
+struct tokenizer tokenizer_create(struct str code, struct str src,
|
|
|
struct tokenizer_options *opts,
|
|
struct tokenizer_options *opts,
|
|
|
enum err *out_err);
|
|
enum err *out_err);
|
|
|
|
|
|
|
@@ -1790,7 +2275,7 @@ bool tokenizer_is_str_lit(struct tokenizer *tkn, struct str str);
|
|
|
# if defined(IMP) || defined(IMP_TOKENIZER)
|
|
# if defined(IMP) || defined(IMP_TOKENIZER)
|
|
|
|
|
|
|
|
struct tokenizer
|
|
struct tokenizer
|
|
|
-tokenizer_create(struct str code, struct path src,
|
|
|
|
|
|
|
+tokenizer_create(struct str code, struct str src,
|
|
|
struct tokenizer_options *opts, enum err *out_err)
|
|
struct tokenizer_options *opts, enum err *out_err)
|
|
|
{
|
|
{
|
|
|
struct tokenizer empty = {0};
|
|
struct tokenizer empty = {0};
|
|
@@ -2340,6 +2825,11 @@ struct cmd {
|
|
|
u64 size;
|
|
u64 size;
|
|
|
u64 cap;
|
|
u64 cap;
|
|
|
} envs;
|
|
} envs;
|
|
|
|
|
+ struct {
|
|
|
|
|
+ i32 *data;
|
|
|
|
|
+ u64 size;
|
|
|
|
|
+ u64 cap;
|
|
|
|
|
+ } fds;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
struct __cmd_create_args {
|
|
struct __cmd_create_args {
|
|
@@ -2413,8 +2903,13 @@ enum err cmd_append_env(struct cmd *_r_ cmd, struct str env,
|
|
|
|
|
|
|
|
struct __cmd_exec_args {
|
|
struct __cmd_exec_args {
|
|
|
struct procs *procs;
|
|
struct procs *procs;
|
|
|
|
|
+ u64 procs_num; /* When it is 0 will use nproc */
|
|
|
bool reset;
|
|
bool reset;
|
|
|
bool search_path;
|
|
bool search_path;
|
|
|
|
|
+ bool verbose;
|
|
|
|
|
+ i32 *fd_in, *fd_out, *fd_err;
|
|
|
|
|
+ struct str_builder *capture_out;
|
|
|
|
|
+ struct str_builder *capture_err;
|
|
|
};
|
|
};
|
|
|
# define cmd_exec(Cmd, OutErr, ...) \
|
|
# define cmd_exec(Cmd, OutErr, ...) \
|
|
|
_cmd_exec( \
|
|
_cmd_exec( \
|
|
@@ -2422,6 +2917,7 @@ struct __cmd_exec_args {
|
|
|
(struct __cmd_exec_args) { \
|
|
(struct __cmd_exec_args) { \
|
|
|
.reset=true, \
|
|
.reset=true, \
|
|
|
.search_path=true, \
|
|
.search_path=true, \
|
|
|
|
|
+ .verbose=false, \
|
|
|
__VA_ARGS__ \
|
|
__VA_ARGS__ \
|
|
|
}, \
|
|
}, \
|
|
|
(OutErr) \
|
|
(OutErr) \
|
|
@@ -2429,6 +2925,9 @@ struct __cmd_exec_args {
|
|
|
enum err _cmd_exec(struct cmd *_r_ cmd, struct __cmd_exec_args args,
|
|
enum err _cmd_exec(struct cmd *_r_ cmd, struct __cmd_exec_args args,
|
|
|
enum err *_r_ out_err);
|
|
enum err *_r_ out_err);
|
|
|
|
|
|
|
|
|
|
+# define cmd_run_cap_out _cmd_run_cap_out
|
|
|
|
|
+char *_cmd_run_cap_out(struct cmd *_r_ cmd, enum err *_r_ out_err);
|
|
|
|
|
+
|
|
|
enum err cmd_clear_args(struct cmd *cmd, enum err *out_err);
|
|
enum err cmd_clear_args(struct cmd *cmd, enum err *out_err);
|
|
|
enum err cmd_destroy(struct cmd *cmd, enum err *out_err);
|
|
enum err cmd_destroy(struct cmd *cmd, enum err *out_err);
|
|
|
|
|
|
|
@@ -2653,6 +3152,9 @@ _cmd_exec(struct cmd *_r_ cmd, struct __cmd_exec_args args,
|
|
|
|
|
|
|
|
i32 pid = -1;
|
|
i32 pid = -1;
|
|
|
i32 status = 0;
|
|
i32 status = 0;
|
|
|
|
|
+ i32 stdin_pipe[2] = {-1};
|
|
|
|
|
+ i32 stdout_pipe[2] = {-1};
|
|
|
|
|
+ i32 stderr_pipe[2] = {-1};
|
|
|
|
|
|
|
|
LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
|
|
LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
|
|
|
LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err);
|
|
LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err);
|
|
@@ -2664,13 +3166,80 @@ _cmd_exec(struct cmd *_r_ cmd, struct __cmd_exec_args args,
|
|
|
|
|
|
|
|
cmd->args.data[cmd->args.size] = NULL;
|
|
cmd->args.data[cmd->args.size] = NULL;
|
|
|
|
|
|
|
|
|
|
+ if ( args.capture_out != NULL ) {
|
|
|
|
|
+ DA_RESERVE(*args.capture_out, 128, perr);
|
|
|
|
|
+ if ( *perr != ERR_OK ) { return *perr; }
|
|
|
|
|
+ if ( pipe(stdout_pipe) < 0 ) { *perr = ERR_FAILED_PIPE; return *perr; }
|
|
|
|
|
+ DA_APPEND(cmd->fds, stdout_pipe[0], perr);
|
|
|
|
|
+ if ( *perr != ERR_OK ) { return *perr; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.capture_err != NULL ) {
|
|
|
|
|
+ DA_RESERVE(*args.capture_err, 128, perr);
|
|
|
|
|
+ if ( *perr != ERR_OK ) { return *perr; }
|
|
|
|
|
+ if ( pipe(stderr_pipe) < 0 ) { *perr = ERR_FAILED_PIPE; return *perr; }
|
|
|
|
|
+ DA_APPEND(cmd->fds, stderr_pipe[0], perr);
|
|
|
|
|
+ if ( *perr != ERR_OK ) { return *perr; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.fd_in != NULL ) {
|
|
|
|
|
+ if ( stdin_pipe[0] == -1 ) {
|
|
|
|
|
+ if ( pipe(stdin_pipe) < 0 ) { *perr = ERR_FAILED_PIPE; return *perr; }
|
|
|
|
|
+ DA_APPEND(cmd->fds, stdin_pipe[1], perr);
|
|
|
|
|
+ if ( *perr != ERR_OK ) { return *perr; }
|
|
|
|
|
+ }
|
|
|
|
|
+ *args.fd_in = stdin_pipe[1];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.fd_out != NULL ) {
|
|
|
|
|
+ if ( stdout_pipe[0] == -1 ) {
|
|
|
|
|
+ if ( pipe(stdout_pipe) < 0 ) { *perr = ERR_FAILED_PIPE; return *perr; }
|
|
|
|
|
+ DA_APPEND(cmd->fds, stdout_pipe[0], perr);
|
|
|
|
|
+ if ( *perr != ERR_OK ) { return *perr; }
|
|
|
|
|
+ }
|
|
|
|
|
+ *args.fd_out = stdout_pipe[0];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.fd_err != NULL ) {
|
|
|
|
|
+ if ( stderr_pipe[0] == -1 ) {
|
|
|
|
|
+ if ( pipe(stderr_pipe) < 0 ) { *perr = ERR_FAILED_PIPE; return *perr; }
|
|
|
|
|
+ DA_APPEND(cmd->fds, stderr_pipe[0], perr);
|
|
|
|
|
+ if ( *perr != ERR_OK ) { return *perr; }
|
|
|
|
|
+ }
|
|
|
|
|
+ *args.fd_err = stderr_pipe[0];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
pid = fork();
|
|
pid = fork();
|
|
|
if ( pid < 0 ) {
|
|
if ( pid < 0 ) {
|
|
|
LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_FORK);
|
|
LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_FORK);
|
|
|
return ERR_FAILED_FORK;
|
|
return ERR_FAILED_FORK;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if ( args.verbose == true ) {
|
|
|
|
|
+ printf("Running: ");
|
|
|
|
|
+ u64 i = 0;
|
|
|
|
|
+ while ( cmd->args.data[i] != NULL ) {
|
|
|
|
|
+ printf("%s ", cmd->args.data[i]);
|
|
|
|
|
+ ++i;
|
|
|
|
|
+ }
|
|
|
|
|
+ printf("\n");
|
|
|
|
|
+ fflush(stdout);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if ( pid == 0 ) {
|
|
if ( pid == 0 ) {
|
|
|
|
|
+ if ( stdin_pipe[0] > 0 ) {
|
|
|
|
|
+ if ( close(stdin_pipe[1]) ) { exit(1); }
|
|
|
|
|
+ if ( dup2(stdin_pipe[0], STDIN_FILENO) < 0 ) { exit(1); }
|
|
|
|
|
+ }
|
|
|
|
|
+ if ( stdout_pipe[1] > 0 ) {
|
|
|
|
|
+ if ( close(stdout_pipe[0]) ) { exit(1); }
|
|
|
|
|
+ if ( dup2(stdout_pipe[1], STDOUT_FILENO) < 0 ) { exit(1); }
|
|
|
|
|
+ }
|
|
|
|
|
+ if ( stderr_pipe[1] > 0 ) {
|
|
|
|
|
+ if ( close(stderr_pipe[0]) ) { exit(1); }
|
|
|
|
|
+ if ( dup2(stderr_pipe[1], STDERR_FILENO) < 0 ) { exit(1); }
|
|
|
|
|
+ }
|
|
|
(
|
|
(
|
|
|
(args.search_path == true)
|
|
(args.search_path == true)
|
|
|
? execvpe
|
|
? execvpe
|
|
@@ -2679,12 +3248,63 @@ _cmd_exec(struct cmd *_r_ cmd, struct __cmd_exec_args args,
|
|
|
exit(1);
|
|
exit(1);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if ( stdin_pipe[0] > 0 ) {
|
|
|
|
|
+ if ( close(stdin_pipe[0]) ) { *perr = ERR_FAILED_CLOSE; return *perr; }
|
|
|
|
|
+ }
|
|
|
|
|
+ if ( stdout_pipe[1] > 0 ) {
|
|
|
|
|
+ if ( close(stdout_pipe[1]) ) { *perr = ERR_FAILED_CLOSE; return *perr; }
|
|
|
|
|
+ }
|
|
|
|
|
+ if ( stderr_pipe[1] > 0 ) {
|
|
|
|
|
+ if ( close(stderr_pipe[1]) ) { *perr = ERR_FAILED_CLOSE; return *perr; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if ( args.reset == true ) {
|
|
if ( args.reset == true ) {
|
|
|
cmd_clear_args(cmd, NULL);
|
|
cmd_clear_args(cmd, NULL);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if ( args.procs != NULL ) {
|
|
if ( args.procs != NULL ) {
|
|
|
|
|
+ u64 nproc = args.procs_num;
|
|
|
|
|
+
|
|
|
DA_APPEND(*args.procs, pid, perr);
|
|
DA_APPEND(*args.procs, pid, perr);
|
|
|
|
|
+ if ( nproc == 0 ) return *perr;
|
|
|
|
|
+
|
|
|
|
|
+ if ( args.procs->size >= nproc ) {
|
|
|
|
|
+ pid = args.procs->data[0];
|
|
|
|
|
+ do {
|
|
|
|
|
+ if ((perr) != ((void * ) 0)) {
|
|
|
|
|
+ if ( * (perr) != ERR_OK) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if ((0) >= ( * args.procs).size) {
|
|
|
|
|
+ if ((perr) != ((void * ) 0)) {
|
|
|
|
|
+ *(perr) = ERR_INDEX_TOO_LARGE;
|
|
|
|
|
+ };
|
|
|
|
|
+ break;
|
|
|
|
|
+ }--( * args.procs).size;
|
|
|
|
|
+ printf("-------------------------------------------------\n");
|
|
|
|
|
+ DA_FOREACH_INDEX(*args.procs, i) {
|
|
|
|
|
+ printf("\t - %ld -> pid: %d\n", i, args.procs->data[i]);
|
|
|
|
|
+ }
|
|
|
|
|
+ printf("-------------------------------------------------\n");
|
|
|
|
|
+ memmove(( * args.procs).data + (0), (( * args.procs).data + (0)) + 1, sizeof( * ( * args.procs).data) * (( * args.procs).size - ((0) + 1)));
|
|
|
|
|
+ memset(( * args.procs).data + ( * args.procs).size, 0, sizeof( * ( * args.procs).data));
|
|
|
|
|
+ } while (0);
|
|
|
|
|
+ /* DA_DELETE(*args.procs, 0, perr); */
|
|
|
|
|
+ if ( *perr != ERR_OK ) return *perr;
|
|
|
|
|
+ if ( waitpid(pid, &status, 0) < 0 ) {
|
|
|
|
|
+ LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_WAITPID);
|
|
|
|
|
+ return ERR_FAILED_WAITPID;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( WIFEXITED(status) == true ) {
|
|
|
|
|
+ if ( WEXITSTATUS(status) != 0 ) {
|
|
|
|
|
+ LIB_SET_IF_NOT_NULL(out_err, ERR_CMD_NON_ZERO_EXIT_CODE);
|
|
|
|
|
+ return ERR_CMD_NON_ZERO_EXIT_CODE;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return *perr;
|
|
return *perr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -2726,6 +3346,11 @@ cmd_destroy(struct cmd *cmd, enum err *out_err)
|
|
|
LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
|
|
LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK);
|
|
|
LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err);
|
|
LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err);
|
|
|
|
|
|
|
|
|
|
+ if ( cmd->fds.data != NULL ) {
|
|
|
|
|
+ DA_FOREACH(cmd->fds, it) { close(*it); }
|
|
|
|
|
+ }
|
|
|
|
|
+ LIB_FREE(cmd->fds.data);
|
|
|
|
|
+
|
|
|
if ( cmd->args.data != NULL ) {
|
|
if ( cmd->args.data != NULL ) {
|
|
|
DA_FOREACH(cmd->args, it) {
|
|
DA_FOREACH(cmd->args, it) {
|
|
|
LIB_FREE(*it);
|
|
LIB_FREE(*it);
|
|
@@ -2803,6 +3428,8 @@ _cmd_go_rebuild_yourself(const char *src, char **argv,
|
|
|
|
|
|
|
|
if ( err == ERR_OK ) execv(argv[0], argv);
|
|
if ( err == ERR_OK ) execv(argv[0], argv);
|
|
|
if ( err == ERR_OK ) exit(0);
|
|
if ( err == ERR_OK ) exit(0);
|
|
|
|
|
+
|
|
|
|
|
+ cmd_destroy(&cmd, NULL);
|
|
|
}
|
|
}
|
|
|
} while(0);
|
|
} while(0);
|
|
|
|
|
|
|
@@ -4249,33 +4876,4 @@ exit:
|
|
|
# undef ALLOC_FUNC
|
|
# undef ALLOC_FUNC
|
|
|
# endif /* LIB_H_ALLOC_FUNC */
|
|
# endif /* LIB_H_ALLOC_FUNC */
|
|
|
|
|
|
|
|
-# ifdef LIB_H_STDBOOL
|
|
|
|
|
-# undef LIB_H_STDBOOL
|
|
|
|
|
-
|
|
|
|
|
-# undef bool
|
|
|
|
|
-# undef true
|
|
|
|
|
-# undef false
|
|
|
|
|
-# endif /* LIB_H_STDBOOL */
|
|
|
|
|
-
|
|
|
|
|
-# ifdef LIB_H_NULL
|
|
|
|
|
-# undef LIB_H_NULL
|
|
|
|
|
-
|
|
|
|
|
-# undef NULL
|
|
|
|
|
-# endif /* LIB_H_NULL */
|
|
|
|
|
-
|
|
|
|
|
-# ifdef LIB_H_UNISTD
|
|
|
|
|
-# undef LIB_H_UNISTD
|
|
|
|
|
-
|
|
|
|
|
-# undef R_OK
|
|
|
|
|
-# undef W_OK
|
|
|
|
|
-# undef X_OK
|
|
|
|
|
-# undef F_OK
|
|
|
|
|
-# endif /* LIB_H_UNISTD */
|
|
|
|
|
-
|
|
|
|
|
-# ifdef LIB_H_STDINT
|
|
|
|
|
-# undef LIB_H_STDINT
|
|
|
|
|
-
|
|
|
|
|
-# undef intmax_t
|
|
|
|
|
-# endif /* LIB_H_STDINT */
|
|
|
|
|
-
|
|
|
|
|
#endif /* LIB_H */
|
|
#endif /* LIB_H */
|