Compare commits

...

3 Commits

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "contrib/doxygen-awesome-css"]
path = contrib/doxygen-awesome-css
url = https://github.com/jothepro/doxygen-awesome-css.git

@ -12,6 +12,17 @@ endif()
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
option(GIT_SUBMODULE "Update git submodules during build" ON)
if(GIT_SUBMODULE)
message(STATUS "Git submodule update")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
message(FATAL_ERROR "git submodule update --init --recursive failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
endif()
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
@ -28,6 +39,8 @@ add_subdirectory(src)
add_subdirectory(demo)
add_subdirectory(doc)
option(BUILD_TESTING "Build tests" ON)
if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR NEO_BUILD_TESTING) AND BUILD_TESTING)
enable_testing()

@ -0,0 +1,57 @@
# See the end of this file for copyright and license terms.
option(BUILD_DOCS "Build documentation" OFF)
option(BUILD_DOCS_HTML "Build documentation in HTML format" ON)
option(BUILD_DOCS_LATEX "Build documentation in LaTEX format" OFF)
option(BUILD_DOCS_RTF "Build documentation in Rich Text Format" OFF)
option(BUILD_DOCS_XML "Build documentation in XML format" OFF)
if(BUILD_DOCS)
find_package(Doxygen REQUIRED)
add_custom_target(neo_docs ALL
DEPENDS neo
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Building documentation"
VERBATIM
)
set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
if(BUILD_DOCS_HTML)
set(neo_BUILD_DOCS_HTML YES)
else()
set(neo_BUILD_DOCS_HTML NO)
endif()
if(BUILD_DOCS_LATEX)
set(neo_BUILD_DOCS_LATEX YES)
else()
set(neo_BUILD_DOCS_LATEX NO)
endif()
if(BUILD_DOCS_RTF)
set(neo_BUILD_DOCS_RTF YES)
else()
set(neo_BUILD_DOCS_RTF NO)
endif()
if(BUILD_DOCS_XML)
set(neo_BUILD_DOCS_XML YES)
else()
set(neo_BUILD_DOCS_XML NO)
endif()
endif()
# This file is part of libneo.
# Copyright (c) 2021 Fefie <owo@fef.moe>.
#
# libneo is non-violent software: you may only use, redistribute,
# and/or modify it under the terms of the CNPLv6+ as found in
# the LICENSE file in the source code root directory or at
# <https://git.pixie.town/thufie/CNPL>.
#
# libneo comes with ABSOLUTELY NO WARRANTY, to the extent
# permitted by applicable law. See the CNPLv6+ for details.

@ -58,7 +58,7 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/../doc/
OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@ -1245,7 +1245,7 @@ HTML_STYLESHEET =
# list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_STYLESHEET = @CMAKE_CURRENT_SOURCE_DIR@/doxygen-awesome.css
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note

@ -0,0 +1 @@
../contrib/doxygen-awesome-css/doxygen-awesome.css

@ -1,7 +1,7 @@
/* See the end of this file for copyright and license terms. */
/**
* @file Main libneo header file providing core functionalities.
* @brief Main libneo header file providing core functionalities.
*/
#pragma once

@ -28,9 +28,9 @@ void yeet(error *err, u32 number, const char *restrict fmt, ...)
__attribute__(( __format__(printf, 3, 4) ));
/**
* Indicate an operation has completed successfully.
* @brief Indicate an operation has completed successfully.
* Functions accepting an `error` pointer must call either `yeet()` or `neat()`,
* or the begavior is undefined.
* or the behavior is undefined.
*
* @param err Error object
*/
@ -55,10 +55,16 @@ void errput(error *err);
*
* Execute the expression after this macro call if the error pointed to
* by `err` is an actual error, i.e. it has been `yeet()`ed to.
* Resources for the error must be released using `nput()`.
* Resources for the error must be released using `errput()`.
*/
#define ncatch(err) if ((err) != nil && (err)->_number != 0)
#ifndef __cplusplus
/**
* @brief Catch an error.
*
* This is just a wrapper intended to piss off C++ developers, and thus
* should be used instead of `ncatch()` wherever possible.
*/
# define catch(err) ncatch(err)
#endif

@ -19,7 +19,7 @@
void nfree(void *ptr);
/**
* Allocate `size` bytes of memory and return a pointer to the memory region.
* @brief Allocate `size` bytes of memory and return a pointer to the memory region.
* The memory is *not* initialized; use `nzalloc()` if you want it to be.
* If `size` is 0, the allocation fails.
* If the allocation fails, the error is set and `nil` is returned.

@ -91,6 +91,12 @@ nbuf_t *nbuf_clone(nbuf_t *buf, error *err);
__byte; \
})
/**
* @brief Iterate over every byte in a buffer.
*
* @param cursor A `const u8 *` to be used as an iteration cursor
* @param buf `nbuf_t *` to iterate over
*/
#define nbuf_foreach(cursor, buf) \
for (cursor = &buf->_data[0]; \
cursor != &buf->_data[nlen(buf)]; \
@ -100,8 +106,8 @@ nbuf_t *nbuf_clone(nbuf_t *buf, error *err);
* @brief Compare two buffers.
*
* If the first buffer is found to be greater than the second one, the return
* value is greater than 0.
* If the two buffers are equal, the return value is zero.
* value is greater than 0.\n
* If the two buffers are equal, the return value is zero.\n
* If the first buffer is found to be less than the second one, the return
* value is less than 0.
*
@ -114,6 +120,14 @@ nbuf_t *nbuf_clone(nbuf_t *buf, error *err);
*/
int nbuf_cmp(const nbuf_t *buf1, const nbuf_t *buf2, error *err);
/**
* @brief Determine whether two buffers are equal.
*
* @param buf1 First `nbuf_t *` to compare
* @param buf2 Second `nbuf_t *` to compare
* @param err Error pointer
* @returns `true` if the two buffers are found to be equal, `false` if not
*/
#define nbuf_eq(buf1, buf2, err) ( (bool)(nbuf_cmp(buf1, buf2, err) == 0) )
/** @} */

@ -55,6 +55,34 @@ int _neo_nput(struct _neo_nref *ref);
ptr = nil; \
})
/**
* @brief Borrow a refcounted structure.
*
* Increment the refcounter of a structure embedding `NREF_FIELD` and return
* a pointer to its `nref_t` field so that it can be stored in your own struct
* that depends on its existence.
*
* The borrowed structure is guaranteed to not be destroyed before you call
* `unborrow()` (unless you make the error of calling `nput()` )
*
* @param ptr Pointer to the refcounted entity to borrow
* @returns An `nref_t *` that must be passed to `unborrow()` when the borrow
* is no longer used
*/
#define borrow(ptr) ({ \
nref_t *__nref = &(ptr)->__neo_nref; \
_neo_nget(__nref); \
__nref; \
})
/**
* @brief Decrement the reference counter of a borrowed structure after usage.
* Call this in the borrowing structure's teardown routine.
*
* @param nref The `nref_t *` returned by `borrow()`
*/
#define unborrow(nref) ((void)_neo_nput(nref))
/**
* @brief Return the current reference count of a structure embedding `NREF_FIELD`.
* You usually shouldn't need this though.

@ -13,6 +13,7 @@
*
* Changing this might require also changing the linker script because of
* alignment requirements.
* @private
*/
struct _neo_nstr_init_info {
nstr_t **dest;
@ -39,21 +40,32 @@ struct _neo_nstr_init_info {
#define nstr_raw(nstr) ((nstr)->_data)
/**
* @brief Statically define a neo string (file scope only).
* @brief Statically initialize a neo string (file scope only).
*
* The string will be initialized before `main` is called.
*
* @param name Name of the `nstr_t *` variable to be declared
* @param name Name of the (already declared) `nstr_t *` to initialize
* @param content A `const char *` with the contents of the string
*/
#define NSTR_DEFINE(name, content) \
nstr_t *name = nil; \
#define NSTR_INIT(name, content) \
__neo_section(.data.__neo.nstr_array) \
struct _neo_nstr_init_info __neo_nstr_init_info_##name = { \
.dest = &name, \
.data = content, \
}
/**
* @brief Statically declare and define a neo string (file scope only).
*
* The string will be initialized before `main` is called.
*
* @param name Name of the `nstr_t *` variable to be declared
* @param content A `const char *` with the contents of the string
*/
#define NSTR_DEFINE(name, content) \
nstr_t *name = nil; \
NSTR_INIT(name, content)
/**
* @brief Copy a regular C string to a neo string.
*
@ -144,6 +156,17 @@ nstr_t *nstrdup(nstr_t *s, error *err);
*/
nstr_t *nstrmul(nstr_t *s, usize n, error *err);
/**
* @brief The same as `nstrmul()`, but `nput()` is called on `s` afterwards.
*
* @param s String to repeat, `nput()` will be called on it
* @param n Total amount of repetitions
* @param err Error pointer
* @returns A new string with the repeated content, unless an error occurred
* @see nstrmul
*/
nstr_t *nstrmul_put(nstr_t *s, usize n, error *err);
/**
* @brief Create a string considting of `n` repetitions of `c`.
*
@ -171,6 +194,18 @@ nstr_t *nchrmul(nchar c, usize n, error *err);
*/
nstr_t *nstrcat(const nstr_t *s1, const nstr_t *s2, error *err);
/**
* @brief The same as `nstrcat()`, but `nput()` is called on `s1` and `s2` afterwards.
*
* @param s1 First string, `nput()` will be called on this
* @param s2 Second string, `nput()` will be called on this
* @param err Error pointer
* @returns A new string instance that consists of the two concatenated ones,
* unless an error occurred
* @see nstrcar
*/
nstr_t *nstrcat_put(nstr_t *s1, nstr_t *s2, error *err);
/**
* @brief Compare two strings character by character.
*
@ -213,6 +248,18 @@ int nstrcmp(const nstr_t *s1, const nstr_t *s2, error *err);
*/
nstr_t *leftpad(nstr_t *s, usize length, nchar fill, error *err);
/**
* @brief The same as `leftpad()`, but `nput()` is called on `s` afterwards
*
* @param s String to expand
* @param length Desired length of the new string
* @param fill Character to fill the space with
* @param err Error pointer
* @returns The new padded string
* @see leftpad
*/
nstr_t *leftpad_put(nstr_t *s, usize length, nchar fill, error *err);
/**
* @brief Iterate over each character in a string.
*

@ -13,34 +13,66 @@
#ifdef __cplusplus
# define nil nullptr
#else
/** @brief Null pointer. */
# define nil ((void *)0)
#endif
#ifndef offsetof
/**
* @brief Get the byte offset of a member within a struct.
*
* @param type Type of the structure
* @param member Name of the member within the struct
* @returns The byte offset of `member` within `type`
*/
# define offsetof(type, member) __builtin_offsetof(type, member)
#endif
#ifndef typeof
/**
* @brief Get the type an expression evaluates to (for generic macros).
*
* @param expr Expression to get the type of
* @returns The type, can be used for casting or declarations
*/
# define typeof(expr) __typeof(expr)
#endif
/** @brief Get the absolute (non negative) value of an integer */
#define nabs(n) ({ \
/* n is an expression, not a variable, evaluate it only once */ \
typeof(n) __neo_local_n = (n); \
__neo_local_n < 0 ? -__neo_local_n : __neo_local_n; \
/**
* @brief Get the absolute (non negative) value of an integer.
*
* @param n The integer
* @returns The absolute value
*/
#define nabs(n) ({ \
typeof(n) __n = (n); \
__n < 0 ? -__n : __n; \
})
/**
* @brief Get the maximum value of two integer expressions.
*
* @param x1 First expression
* @param x2 Second expression
* @returns The bigger value
*/
#define nmax(x1, x2) ({ \
typeof(x1) __x1 = (x1); \
typeof(x2) __x2 = (x2); \
__x1 > __x2 ? __x1 : __x2; \
})
/**
* @brief Get the minimum value of two integer expressions.
*
* @param x1 First expression
* @param x2 Second expression
* @returns The smaller value
*/
#define nmin(x1, x2) ({ \
typeof(x1) __x1 = (x1); \
typeof(x2) __x2 = (x2); \
__x1 < __x2 ? __x1 : x2; \
__x1 < __x2 ? __x1 : __x2; \
})
/**
@ -54,7 +86,7 @@
*/
#define nlen(thing) ((thing)->__neo_nlen)
/* @} */
/** @} */
/*
* This file is part of libneo.

@ -10,26 +10,38 @@
* @{
*/
/** @brief Signed 8-bit integer. */
typedef __INT8_TYPE__ i8;
/** @brief Signed 16-bit integer. */
typedef __INT16_TYPE__ i16;
/** @brief Signed 32-bit integer. */
typedef __INT32_TYPE__ i32;
/** @brief Signed 64-bit integer. */
typedef __INT64_TYPE__ i64;
/** @brief Unsigned 8-bit integer. */
typedef __UINT8_TYPE__ u8;
/** @brief Alias for @a `u8`. */
typedef __UINT8_TYPE__ byte;
/** @brief Unsigned 16-bit integer. */
typedef __UINT16_TYPE__ u16;
/** @brief Unsigned 32-bit integer. */
typedef __UINT32_TYPE__ u32;
/** @brief Unsigned 64-bit integer. */
typedef __UINT64_TYPE__ u64;
/** @brief Platform-dependent unsigned integer for storing sizes. */
typedef __SIZE_TYPE__ usize;
/** @brief Platform-dependent signed integer for storing sizes. */
typedef __PTRDIFF_TYPE__ isize;
/** @brief A single Unicode character (32 bits) */
/** @brief A single Unicode character (32 bits). */
typedef u32 nchar;
/** @brief Single precision (32-bit) floating-point number. */
typedef float f32;
/** @brief Double precision (64-bit) floating-point number. */
typedef double f64;
typedef long double f128;
/** @} */
@ -47,7 +59,7 @@ typedef long double f128;
/**
* @brief Declare a length field in a structure.
* This makes it compatible with the `nlen` macro.
* This makes it compatible with the `nlen()` macro.
*
* @param name field name, will be of type `usize`
*
@ -59,6 +71,7 @@ typedef long double f128;
volatile const usize __neo_nlen; \
}
/** @private */
struct _neo_nref {
void (*_destroy)(void *);
/** byte offset into the struct this is embedded in */
@ -85,6 +98,7 @@ typedef struct _neo_nref nref_t;
*/
#define NREF_FIELD nref_t __neo_nref
/** @private */
struct _neo_nbuf {
NREF_FIELD;
NLEN_FIELD(_size);
@ -102,6 +116,7 @@ struct _neo_nbuf {
*/
typedef struct _neo_nbuf nbuf_t;
/** @private */
struct _neo_nstr {
/* The *amount of Unicode code points*, NOT amount of bytes */
NLEN_FIELD(_len);
@ -122,6 +137,7 @@ struct _neo_nstr {
*/
typedef struct _neo_nstr nstr_t;
/** @private */
struct _neo_error {
nstr_t *_message;
u32 _number;

@ -1,9 +1,5 @@
/* See the end of this file for copyright and license terms. */
/**
* @file Hashtable API
*/
#pragma once
#ifdef __cplusplus
@ -15,12 +11,14 @@ extern "C" {
#include "neo/_types.h"
#include "neo/list.h"
/** @private */
struct _neo_hashtab_entry {
listnode_t link;
nbuf_t *key;
void *val;
};
/** @private */
struct _neo_hashtab {
NLEN_FIELD(_len);
NREF_FIELD;
@ -119,6 +117,7 @@ void *hashtab_del(hashtab_t *table, nbuf_t *key, error *err);
* the iteration stops if the return value is nonzero
* @param extra Optional pointer that is passed as an extra argument to the
* callback function
* @param err Error pointer
* @returns The last return value of the callback, unless an error occurred
*/
int hashtab_foreach(hashtab_t *table,

@ -1,9 +1,5 @@
/* See the end of this file for copyright and license terms. */
/**
* @file List API
*/
#pragma once
#ifdef __cplusplus
@ -15,6 +11,7 @@ extern "C" {
struct _neo_list;
/** @private */
struct _neo_listnode {
struct _neo_listnode *_next;
struct _neo_listnode *_prev;
@ -27,6 +24,7 @@ struct _neo_listnode {
*/
typedef struct _neo_listnode listnode_t;
/** @private */
struct _neo_list {
struct _neo_listnode _root;
NLEN_FIELD(_len);
@ -46,6 +44,7 @@ typedef struct _neo_list list_t;
* @param casted `struct *` that the @a `listnode_t *` was casted out to
* @param list @a `list_t *` storing the root @a `listnode_t`
* @param member Name of the @a `listnode_t` member embedded within the `struct *`
* @private
*/
#define _neo_list_is_root(casted, list, member) \
( &(casted)->member == &(list)->_root )
@ -55,15 +54,19 @@ typedef struct _neo_list list_t;
* external compiler settings which my complain about calculating with void *
*/
/** @private */
#define _neo_list_first(list, type, member) \
((type *)( (u8 *)((list)->_root._next) - offsetof(type, member) ))
/** @private */
#define _neo_list_last(list, type, member) \
((type *)( (u8 *)((list)->_root._prev) - offsetof(type, member) ))
/** @private */
#define _neo_list_next(current, member) \
((typeof(current))( (u8 *)((current)->member._next) - offsetof(typeof(*(current)), member) ))
/** @private */
#define _neo_list_prev(current, member) \
((typeof(current))( (u8 *)((current)->member._prev) - offsetof(typeof(*(current)), member) ))
@ -74,7 +77,7 @@ typedef struct _neo_list list_t;
*/
/**
* Initialize a list.
* @brief Initialize a list.
*
* @param list The list
*/
@ -104,7 +107,7 @@ void list_del(listnode_t *node);
void list_add_first(list_t *list, listnode_t *new_node);
/**
* Insert a new node after the specified list node.
* @brief Insert a new node after the specified list node.
*
* @param pos List node to insert the new node after
* @param new_node Node to insert after the specified position
@ -112,7 +115,7 @@ void list_add_first(list_t *list, listnode_t *new_node);
void list_insert(listnode_t *pos, listnode_t *new_node);
/**
* Insert a new node before the specified list node.
* @brief Insert a new node before the specified list node.
*
* @param pos List node to insert the new node before
* @param new_node Node to insert before the specified position
@ -126,7 +129,7 @@ void list_insert_before(listnode_t *pos, listnode_t *new_node);
*
* @param cursor `type *` to use as a cursor
* @param list `list_t *` to iterate over
* @param member Name of the `listnode_t` member embedded within \a `cursor`
* @param member Name of the `listnode_t` member embedded within `cursor`
*/
#define list_foreach(cursor, list, member) \
for (typeof(cursor) __tmp = _neo_list_next( \
@ -143,7 +146,7 @@ void list_insert_before(listnode_t *pos, listnode_t *new_node);
*
* @param cursor `type *` to use as a cursor
* @param list `list_t *` to iterate over
* @param member Name of the `listnode_t` member embedded within \a `cursor`
* @param member Name of the `listnode_t` member embedded within `cursor`
*/
#define list_foreach_reverse(cursor, list, member) \
for (typeof(cursor) __tmp = _neo_list_prev( \

@ -1,7 +1,16 @@
/* See the end of this file for copyright and license terms. */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "neo/_toolchain.h"
#include "neo/_types.h"
/**
* @file Conversion utilities for raw UTF.
* @defgroup utf Raw UTF Handling
*
* Note that libneo strings already have native UTF-8 support, so you only
* really need this if you explicitly need to deal with different encodings or
@ -12,17 +21,10 @@
* for them if the string contains a malformed UTF sequence.
*
* Believe me when i say you do not want to use these.
*
* @{
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "neo/_toolchain.h"
#include "neo/_types.h"
/**
* @brief Check whether a NUL terminated string is valid UTF-8.
*
@ -37,7 +39,7 @@ usize utf8_check(const char *restrict s, error *err);
/**
* @brief Check whether a NUL terminated string is valid UTF-8.
* At most `maxsize + 3` bytes are read (this function uses `utf8_to_nchr` internally).
* At most `maxsize + 3` bytes are read (this function uses `utf8_to_nchr()` internally).
*
* If a NUL terminator is encountered before `maxsize` bytes, reading stops
* before the specified size. If the string contains any malformed code
@ -55,7 +57,7 @@ usize utf8_ncheck(const char *restrict s, usize maxsize, error *err);
* @brief Compute the length of a raw UTF-8 encoded, NUL terminated string.
*
* The string is *not* checked for malformed code sequences,
* use `utf8_check` for that.
* use `utf8_check()` for that.
*
* @param s String to get the length of
* @returns String length as in Unicode code points (not bytes),
@ -109,6 +111,8 @@ usize utf8_from_nchr(char *restrict dest, nchar c, error *err);
*/
usize utf8_to_nchr(nchar *c, const char *restrict utf8chr, error *err);
/** @} */
#ifdef __cplusplus
}; /* extern "C" */
#endif

@ -17,50 +17,6 @@ configure_file(
${CMAKE_BINARY_DIR}/include/neo/buildconfig.h
)
option(BUILD_DOCS "Build documentation" ON)
option(BUILD_DOCS_HTML "Build documentation in HTML format" ON)
option(BUILD_DOCS_LATEX "Build documentation in LaTEX format" OFF)
option(BUILD_DOCS_RTF "Build documentation in Rich Text Format" OFF)
option(BUILD_DOCS_XML "Build documentation in XML format" OFF)
if(BUILD_DOCS)
find_package(Doxygen REQUIRED)
set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/../doc/Doxyfile.in)
set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
if(BUILD_DOCS_HTML)
set(neo_BUILD_DOCS_HTML YES)
else()
set(neo_BUILD_DOCS_HTML NO)
endif()
if(BUILD_DOCS_LATEX)
set(neo_BUILD_DOCS_LATEX YES)
else()
set(neo_BUILD_DOCS_LATEX NO)
endif()
if(BUILD_DOCS_RTF)
set(neo_BUILD_DOCS_RTF YES)
else()
set(neo_BUILD_DOCS_RTF NO)
endif()
if(BUILD_DOCS_XML)
set(neo_BUILD_DOCS_XML YES)
else()
set(neo_BUILD_DOCS_XML NO)
endif()
add_custom_target(neo_docs ALL
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Building documentation"
VERBATIM
)
endif()
target_include_directories(neo PUBLIC ../include)
target_include_directories(neo PRIVATE
./include

@ -68,6 +68,16 @@ nstr_t *leftpad(nstr_t *s, usize len, nchar fillchr, error *err)
return padded;
}
nstr_t *leftpad_put(nstr_t *s, usize len, nchar fillchr, error *err)
{
nstr_t *padded = leftpad(s, len, fillchr, err);
catch(err) {
return nil;
}
nput(s);
return padded;
}
/*
* This file is part of libneo.
* Copyright (c) 2021 Fefie <owo@fef.moe>.

@ -41,6 +41,18 @@ nstr_t *nstrcat(const nstr_t *s1, const nstr_t *s2, error *err)
return ret;
}
nstr_t *nstrcat_put(nstr_t *s1, nstr_t *s2, error *err)
{
nstr_t *cat = nstrcat(s1, s2, err);
catch(err) {
return nil;
}
nput(s1);
nput(s2);
return cat;
}
/*
* This file is part of libneo.
* Copyright (c) 2021 Fefie <owo@fef.moe>.

@ -39,6 +39,17 @@ nstr_t *nstrmul(nstr_t *s, usize n, error *err)
return ret;
}
nstr_t *nstrmul_put(nstr_t *s, usize n, error *err)
{
nstr_t *mul = nstrmul(s, n, err);
catch(err) {
return nil;
}
nput(s);
return mul;
}
nstr_t *nchrmul(nchar c, usize n, error *err)
{
if (n == 0)

Loading…
Cancel
Save