I haven't pushed this since it is my first time attempting the gnulib
header wizardry and doing anything of value in Autoconf.

The configure check should check for unique values of LITTLE_ENDIAN
and BIG_ENDIAN, and that BYTE_ORDER is defined to one of them. POSIX
doesn't require PDP_ENDIAN and I would rather not think about it. :)

Then it checks for uint16_t, uint32_t, and uint64_t being defined and
the existence of the be16toh macros/functions and friends.

Let me know if I missed anything. Other than the docs and test module
which I can do later today (assuming this patch is decent enough).

Collin
From fe97691b765e57a9c5ea35dca5cb9502d284fb2b Mon Sep 17 00:00:00 2001
From: Collin Funk <collin.fu...@gmail.com>
Date: Mon, 13 May 2024 04:43:18 -0700
Subject: [PATCH] endian: New module.

* modules/endian: New file.
* lib/endian.in.h: New file, based on POSIX draft and glibc.
* m4/endian_h.m4: New file, checks for required types and macro/function
definitions.
---
 ChangeLog       |  8 +++++
 lib/endian.in.h | 89 +++++++++++++++++++++++++++++++++++++++++++++++++
 m4/endian_h.m4  | 68 +++++++++++++++++++++++++++++++++++++
 modules/endian  | 40 ++++++++++++++++++++++
 4 files changed, 205 insertions(+)
 create mode 100644 lib/endian.in.h
 create mode 100644 m4/endian_h.m4
 create mode 100644 modules/endian

diff --git a/ChangeLog b/ChangeLog
index b1cc7ffcf0..91acd31590 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2024-05-13  Collin Funk  <collin.fu...@gmail.com>
+
+	endian: New module.
+	* modules/endian: New file.
+	* lib/endian.in.h: New file, based on POSIX draft and glibc.
+	* m4/endian_h.m4: New file, checks for required types and macro/function
+	definitions.
+
 2024-05-13  Paul Eggert  <egg...@cs.ucla.edu>
 
 	stdbit: port to theoretical platforms
diff --git a/lib/endian.in.h b/lib/endian.in.h
new file mode 100644
index 0000000000..6b287760a5
--- /dev/null
+++ b/lib/endian.in.h
@@ -0,0 +1,89 @@
+/* endian.h - Byte order macros
+
+   Copyright 2024 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Collin Funk.  */
+
+#ifndef _GL_ENDIAN_H
+#define _GL_ENDIAN_H 1
+
+/* This file uses WORDS_BIGENDIAN.  */
+#if !_GL_CONFIG_H_INCLUDED
+ #error "Please include config.h first."
+#endif
+
+/* Byteswap macros.  */
+#include <byteswap.h>
+
+/* Define uint16_t, uint32_t, and uint64_t.  */
+#include <stdint.h>
+
+#define LITTLE_ENDIAN 1234
+#define BIG_ENDIAN 4321
+
+#ifdef WORDS_BIGENDIAN
+# define BYTE_ORDER BIG_ENDIAN
+#else
+# define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+
+/* Big endian to host.  */
+# define be16toh(x) bswap_16 (x)
+# define be32toh(x) bswap_32 (x)
+# define be64toh(x) bswap_64 (x)
+
+/* Host to big endian.  */
+# define htobe16(x) bswap_16 (x)
+# define htobe32(x) bswap_32 (x)
+# define htobe64(x) bswap_64 (x)
+
+/* Host to little endian.  */
+# define htole16(x) ((uint16_t) (x))
+# define htole32(x) ((uint32_t) (x))
+# define htole64(x) ((uint64_t) (x))
+
+/* Little endian to host.  */
+# define le16toh(x) ((uint16_t) (x))
+# define le32toh(x) ((uint32_t) (x))
+# define le64toh(x) ((uint64_t) (x))
+
+#else /* BYTE_ORDER == BIG_ENDIAN */
+
+/* Big endian to host.  */
+# define be16toh(x) ((uint16_t) (x))
+# define be32toh(x) ((uint32_t) (x))
+# define be64toh(x) ((uint64_t) (x))
+
+/* Host to big endian.  */
+# define htobe16(x) ((uint16_t) (x))
+# define htobe32(x) ((uint32_t) (x))
+# define htobe64(x) ((uint64_t) (x))
+
+/* Host to little endian.  */
+# define htole16(x) bswap_16 (x)
+# define htole32(x) bswap_32 (x)
+# define htole64(x) bswap_64 (x)
+
+/* Little endian to host.  */
+# define le16toh(x) bswap_16 (x)
+# define le32toh(x) bswap_32 (x)
+# define le64toh(x) bswap_64 (x)
+
+#endif
+
+#endif /* _GL_ENDIAN_H */
diff --git a/m4/endian_h.m4 b/m4/endian_h.m4
new file mode 100644
index 0000000000..2c4a781b73
--- /dev/null
+++ b/m4/endian_h.m4
@@ -0,0 +1,68 @@
+# endian_h.m4
+# serial 1
+dnl Copyright 2024 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl A placeholder for <endian.h>, for platforms that have issues.
+
+AC_DEFUN_ONCE([gl_ENDIAN_H],
+[
+  AC_REQUIRE([gl_BIGENDIAN])
+
+  dnl Check for the header.
+  AC_CHECK_HEADERS_ONCE([endian.h])
+
+  dnl Check macros and type definitions.
+  if test $ac_cv_header_endian_h = yes; then
+    AC_CACHE_CHECK([if endian.h conforms to POSIX],
+      [gl_cv_header_working_endian_h],
+      [gl_cv_header_working_endian_h=no
+       AC_COMPILE_IFELSE([
+         AC_LANG_PROGRAM(
+[[
+#include <endian.h>
+]],
+[[
+#if LITTLE_ENDIAN == BIG_ENDIAN
+# error "Endian macros not unique."
+#endif
+#if BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN
+# error "Byte order not defined."
+#endif
+
+/* Check for uint16_t, uint32_t, uint64_t along with
+   byte order conversion macros/functions.  */
+
+/* Big endian to host.  */
+uint16_t value16_1 = be16toh (0);
+uint32_t value32_1 = be32toh (0);
+uint64_t value64_1 = be64toh (0);
+
+/* Host to big endian.  */
+uint16_t value16_2 = htobe16 (0);
+uint32_t value32_2 = htobe32 (0);
+uint64_t value64_2 = htobe64 (0);
+
+/* Host to little endian.  */
+uint16_t value16_3 = htole16 (0);
+uint32_t value32_3 = htole32 (0);
+uint64_t value64_3 = htole64 (0);
+
+/* Little endian to host.  */
+uint16_t value16_4 = le16toh (0);
+uint32_t value32_4 = le32toh (0);
+uint64_t value64_4 = le64toh (0);
+
+]])],
+         [gl_cv_header_working_endian_h=yes],
+         [gl_cv_header_working_endian_h=no])
+      ])
+    if test $gl_cv_header_working_endian_h = yes; then
+      GL_GENERATE_ENDIAN_H=false
+    else
+      GL_GENERATE_ENDIAN_H=true
+    fi
+  fi
+])
diff --git a/modules/endian b/modules/endian
new file mode 100644
index 0000000000..f954abb1f4
--- /dev/null
+++ b/modules/endian
@@ -0,0 +1,40 @@
+Description:
+A POSIX-like endian.h.
+
+Files:
+lib/endian.in.h
+m4/endian_h.m4
+
+Depends-on:
+byteswap                [$GL_GENERATE_ENDIAN_H]
+stdint                  [$GL_GENERATE_ENDIAN_H]
+
+configure.ac:
+gl_ENDIAN_H
+gl_CONDITIONAL_HEADER([endian.h])
+AC_PROG_MKDIR_P
+
+Makefile.am:
+BUILT_SOURCES += $(ENDIAN_H)
+
+# We need the following in order to create <endian.h> when the system
+# doesn't have one that works with the given compiler.
+if GL_GENERATE_ENDIAN_H
+endian.h: endian.in.h $(top_builddir)/config.status
+@NMD@	$(AM_V_GEN)$(MKDIR_P) '%reldir%'
+	$(gl_V_at)cp $(srcdir)/endian.in.h $@-t
+	$(AM_V_at)mv $@-t $@
+else
+endian.h: $(top_builddir)/config.status
+	rm -f $@
+endif
+MOSTLYCLEANFILES += endian.h endian.h-t
+
+Include:
+<endian.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.45.0

Reply via email to