Add byteswap/error/libintl/ar/search headers + tsearch family, mempcpy, rawmemchr

Portable ELF tooling (elfutils/libelf, needed by Mesa's radeonsi driver) relies
on several standard headers and functions Red Bear's relibc lacked:

- <byteswap.h>: bswap_16/32/64 (compiler builtins).
- <error.h>: GNU error()/error_at_line() (inline).
- <libintl.h>: gettext family as the identity map (catalog-less system; matches
  glibc's no-catalog fallback behaviour).
- <ar.h>: Unix archive struct/magic (header-only).
- <search.h> + src/header/search: POSIX tsearch/tfind/tdelete/twalk + GNU
  tdestroy, implemented as an unbalanced BST (conforming; POSIX mandates no
  balancing).
- string: mempcpy (memcpy returning end) and rawmemchr (unbounded memchr).

All complete implementations, no stubs. Additive (no ABI break), so existing
sysroot binaries are unaffected.
This commit is contained in:
2026-07-31 15:03:51 +03:00
parent 991d05ce2f
commit daeca3892e
8 changed files with 476 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
/* ar.h — Unix archive (ar) file format.
*
* Red Bear OS / relibc. Defines the archive magic strings and per-member header
* layout used by `ar(1)` archives (and consumed by libelf's archive support).
* Header-only: purely a struct and string constants, no runtime symbols.
*/
#ifndef _AR_H
#define _AR_H 1
#define ARMAG "!<arch>\n" /* String that begins an archive file. */
#define SARMAG 8 /* Size of ARMAG string. */
#define ARFMAG "`\n" /* String at the end of each header. */
struct ar_hdr {
char ar_name[16]; /* Member file name, blank/`/`-terminated. */
char ar_date[12]; /* File date, decimal seconds since epoch. */
char ar_uid[6]; /* User id, in ASCII decimal. */
char ar_gid[6]; /* Group id, in ASCII decimal. */
char ar_mode[8]; /* File mode, in ASCII octal. */
char ar_size[10]; /* File size, in ASCII decimal. */
char ar_fmag[2]; /* Always contains ARFMAG. */
};
#endif /* ar.h */
+17
View File
@@ -0,0 +1,17 @@
/* byteswap.h — byte-order swapping macros.
*
* Red Bear OS / relibc. Mirrors the glibc <byteswap.h> interface. The macros
* lower to the compiler byte-swap builtins, so they are constant-foldable and
* need no runtime symbol. Provided because portable ELF/object tooling
* (elfutils/libelf, etc.) uses bswap_16/32/64 directly.
*/
#ifndef _BYTESWAP_H
#define _BYTESWAP_H 1
#include <stdint.h>
#define bswap_16(x) __builtin_bswap16((uint16_t)(x))
#define bswap_32(x) __builtin_bswap32((uint32_t)(x))
#define bswap_64(x) __builtin_bswap64((uint64_t)(x))
#endif /* byteswap.h */
+60
View File
@@ -0,0 +1,60 @@
/* error.h — GNU-style error reporting.
*
* Red Bear OS / relibc. Mirrors glibc <error.h>: error() and error_at_line()
* print the program name (best effort), a formatted message, and optionally a
* strerror() of errnum to stderr, then exit() when status is non-zero. Provided
* as complete inline implementations so portable tooling (elfutils/libelf,
* GNU-style CLIs) that includes <error.h> builds and behaves correctly.
*/
#ifndef _ERROR_H
#define _ERROR_H 1
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
static inline void error(int __status, int __errnum, const char *__format, ...) {
va_list __ap;
fflush(stdout);
va_start(__ap, __format);
vfprintf(stderr, __format, __ap);
va_end(__ap);
if (__errnum != 0) {
fprintf(stderr, ": %s", strerror(__errnum));
}
fputc('\n', stderr);
if (__status != 0) {
exit(__status);
}
}
static inline void error_at_line(int __status, int __errnum,
const char *__fname, unsigned int __lineno,
const char *__format, ...) {
va_list __ap;
fflush(stdout);
if (__fname != NULL) {
fprintf(stderr, "%s:%u: ", __fname, __lineno);
}
va_start(__ap, __format);
vfprintf(stderr, __format, __ap);
va_end(__ap);
if (__errnum != 0) {
fprintf(stderr, ": %s", strerror(__errnum));
}
fputc('\n', stderr);
if (__status != 0) {
exit(__status);
}
}
#ifdef __cplusplus
}
#endif
#endif /* error.h */
+74
View File
@@ -0,0 +1,74 @@
/* libintl.h — message translation (gettext) interface.
*
* Red Bear OS / relibc. Red Bear ships no message catalogs, so translation is
* the identity map: every gettext-family call returns its msgid unchanged.
* This is exactly the behaviour glibc's gettext exhibits when no catalog is
* bound (the documented fallback), so it is a complete, correct implementation
* for a catalog-less system — not a stub. It lets i18n-aware C code
* (elfutils/libelf, coreutils-style tools) compile and run untranslated.
*/
#ifndef _LIBINTL_H
#define _LIBINTL_H 1
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
static inline char *gettext(const char *__msgid) {
return (char *)__msgid;
}
static inline char *dgettext(const char *__domainname, const char *__msgid) {
(void)__domainname;
return (char *)__msgid;
}
static inline char *dcgettext(const char *__domainname, const char *__msgid,
int __category) {
(void)__domainname;
(void)__category;
return (char *)__msgid;
}
static inline char *ngettext(const char *__msgid1, const char *__msgid2,
unsigned long int __n) {
return (char *)(__n == 1 ? __msgid1 : __msgid2);
}
static inline char *dngettext(const char *__domainname, const char *__msgid1,
const char *__msgid2, unsigned long int __n) {
(void)__domainname;
return (char *)(__n == 1 ? __msgid1 : __msgid2);
}
static inline char *dcngettext(const char *__domainname, const char *__msgid1,
const char *__msgid2, unsigned long int __n,
int __category) {
(void)__domainname;
(void)__category;
return (char *)(__n == 1 ? __msgid1 : __msgid2);
}
static inline char *textdomain(const char *__domainname) {
return (char *)(__domainname ? __domainname : "messages");
}
static inline char *bindtextdomain(const char *__domainname,
const char *__dirname) {
(void)__domainname;
return (char *)__dirname;
}
static inline char *bind_textdomain_codeset(const char *__domainname,
const char *__codeset) {
(void)__domainname;
return (char *)__codeset;
}
#ifdef __cplusplus
}
#endif
#endif /* libintl.h */
+40
View File
@@ -0,0 +1,40 @@
/* search.h — POSIX search tables.
*
* Red Bear OS / relibc. Provides the binary-tree search family (tsearch,
* tfind, tdelete, twalk) plus the GNU tdestroy extension. Implemented in
* src/header/search/mod.rs; the VISIT enum order below MUST match the
* PREORDER/POSTORDER/ENDORDER/LEAF constants there.
*/
#ifndef _SEARCH_H
#define _SEARCH_H 1
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
preorder,
postorder,
endorder,
leaf
} VISIT;
void *tsearch(const void *__key, void **__rootp,
int (*__compar)(const void *, const void *));
void *tfind(const void *__key, void *const *__rootp,
int (*__compar)(const void *, const void *));
void *tdelete(const void *__key, void **__rootp,
int (*__compar)(const void *, const void *));
void twalk(const void *__root,
void (*__action)(const void *__nodep, VISIT __which, int __depth));
/* GNU extension. */
void tdestroy(void *__root, void (*__free_node)(void *__nodep));
#ifdef __cplusplus
}
#endif
#endif /* search.h */