Signed-off-by: Jose E. Marchesi <[email protected]>

ChangeLog

        * libga68/README: New file.
        * libga68/ga68-alloc.c: Likewise.
        * libga68/ga68-error.c: Likewise.
        * libga68/ga68-posix.c: Likewise.
        * libga68/ga68-standenv.c: Likewise.
        * libga68/ga68-unistr.c: Likewise.
        * libga68/ga68.h: Likewise.
        * libga68/libga68.c: Likewise.
        * libga68/libga68.spec.in: Likewise.
---
 libga68/README          |   2 +
 libga68/ga68-alloc.c    | 114 ++++++++
 libga68/ga68-error.c    | 151 ++++++++++
 libga68/ga68-posix.c    | 403 ++++++++++++++++++++++++++
 libga68/ga68-standenv.c |  48 ++++
 libga68/ga68-unistr.c   | 615 ++++++++++++++++++++++++++++++++++++++++
 libga68/ga68.h          | 122 ++++++++
 libga68/libga68.c       |  52 ++++
 libga68/libga68.spec.in |  11 +
 9 files changed, 1518 insertions(+)
 create mode 100644 libga68/README
 create mode 100644 libga68/ga68-alloc.c
 create mode 100644 libga68/ga68-error.c
 create mode 100644 libga68/ga68-posix.c
 create mode 100644 libga68/ga68-standenv.c
 create mode 100644 libga68/ga68-unistr.c
 create mode 100644 libga68/ga68.h
 create mode 100644 libga68/libga68.c
 create mode 100644 libga68/libga68.spec.in

diff --git a/libga68/README b/libga68/README
new file mode 100644
index 00000000000..23929a60451
--- /dev/null
+++ b/libga68/README
@@ -0,0 +1,2 @@
+This is the GNU Algol 68 run-time library.  It provides the run-time
+components needed by programs compiled by the ga68 compiler.
diff --git a/libga68/ga68-alloc.c b/libga68/ga68-alloc.c
new file mode 100644
index 00000000000..1cf922eb211
--- /dev/null
+++ b/libga68/ga68-alloc.c
@@ -0,0 +1,114 @@
+/* Run-time routines for memory allocation.
+
+   Copyright (C) 2025 Jose E. Marchesi.
+
+   GCC is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   GCC 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 General Public License for more
+   details.
+
+   Under Section 7 of GPL version 3, you are granted additional permissions
+   described in the GCC Runtime Library Exception, version 3.1, as published by
+   the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and a copy
+   of the GCC Runtime Library Exception along with this program; see the files
+   COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+
+#include "ga68.h"
+
+/* Heap allocation routines.  */
+
+void
+_libga68_free_internal (void *pt)
+{
+  free (pt);
+}
+
+void *
+_libga68_malloc_internal (size_t size)
+{
+  void *res = (void *) malloc (size);
+  if (!res)
+    _libga68_abort ("Virtual memory exhausted\n");
+  return res;
+}
+
+#if LIBGA68_WITH_GC
+#include <gc/gc.h>
+
+void
+_libga68_init_heap (void)
+{
+  if (!GC_is_init_called ())
+    {
+      GC_INIT ();
+      /*      GC_allow_register_threads (); */
+    }
+}
+
+void *
+_libga68_realloc (void *ptr, size_t size)
+{
+  void *res = (void *) GC_realloc (ptr, size);
+  if (!res)
+    _libga68_abort ("Virtual memory exhausted\n");
+  return res;
+}
+
+void *
+_libga68_realloc_unchecked (void *ptr, size_t size)
+{
+  void *res = (void *) GC_realloc (ptr, size);
+  return res;
+}
+
+void *
+_libga68_malloc (size_t size)
+{
+  void *res = (void *) GC_malloc (size);
+  if (!res)
+    _libga68_abort ("Virtual memory exhausted\n");
+  return res;
+}
+
+#else
+
+void
+_libga68_init_heap (void)
+{
+}
+
+void *
+_libga68_realloc (void *ptr, size_t size)
+{
+  void *res = (void *) realloc (ptr, size);
+  if (!res)
+    _libga68_abort ("Virtual memory exhausted\n");
+  return res;
+}
+
+void *
+_libga68_realloc_unchecked (void *ptr, size_t size)
+{
+  void *res = (void *) realloc (ptr, size);
+  return res;
+}
+
+void *
+_libga68_malloc (size_t size)
+{
+  void *res = (void *) malloc (size);
+  if (!res)
+    _libga68_abort ("Virtual memory exhausted\n");
+  return res;
+}
+
+#endif /* !LIBGA68_WITH_GC */
diff --git a/libga68/ga68-error.c b/libga68/ga68-error.c
new file mode 100644
index 00000000000..28f71659645
--- /dev/null
+++ b/libga68/ga68-error.c
@@ -0,0 +1,151 @@
+/* Support run-time routines for error handling.
+
+   Copyright (C) 2025 Jose E. Marchesi.
+
+   GCC is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   GCC 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 General Public License for more
+   details.
+
+   Under Section 7 of GPL version 3, you are granted additional permissions
+   described in the GCC Runtime Library Exception, version 3.1, as published by
+   the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and a copy
+   of the GCC Runtime Library Exception along with this program; see the files
+   COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h> /* For abort.  */
+
+#include "ga68.h"
+
+/* Run-time error handling.
+
+   Please use the following format when outputing runtime error messages:
+
+     FILE:LINE:[COLUMN:] TEXT
+
+   This keeps the output aligned with other runtime libraries such as the
+   sanitizers.  */
+
+/* Emit a formatted error message to the standard output and then terminate the
+   process with an error code.  */
+
+void
+_libga68_abort (const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  vfprintf (stderr, fmt, ap);
+  abort ();
+  va_end (ap);
+}
+
+/* Assertion failure.  */
+
+void
+_libga68_assert (const char *filename, unsigned int lineno)
+{
+  _libga68_abort ("%s:%u: runtime error: ASSERT failure\n",
+                filename, lineno);
+}
+
+/* Attempt to dereference NIL failure.  */
+
+void
+_libga68_derefnil (const char *filename, unsigned int lineno)
+{
+  _libga68_abort ("%s:%u: runtime error: attempt to dereference NIL\n",
+                 filename, lineno);
+}
+
+/* Invalid character expression.  */
+
+void
+_libga68_invalidcharerror (const char *filename, unsigned int lineno,
+                          int c)
+{
+  if (c < 0)
+    _libga68_abort ("%s:%u: runtime error: %d is not a valid character 
point\n",
+                   filename, lineno, c);
+  _libga68_abort ("%s:%u: runtime error: U+%x is not a valid character 
point\n",
+                 filename, lineno, c);
+}
+
+/* Out of bounds error in bits ELEM operator.  */
+
+void
+_libga68_bitsboundserror (const char *filename, unsigned int lineno,
+                         ssize_t pos)
+{
+  _libga68_abort ("%s:%u: runtime error: bound %zd out of range in ELEM\n",
+                 filename, lineno, pos);
+}
+
+/* Unreachable error.  */
+
+void
+_libga68_unreachable (const char *filename, unsigned int lineno)
+{
+  _libga68_abort ("%s:%u: runtime error: unreachable reached\n",
+                 filename, lineno);
+}
+
+/* Lower bound failure.  */
+
+void
+_libga68_lower_bound (const char *filename, unsigned int lineno,
+                          ssize_t index, ssize_t lower_bound)
+{
+  _libga68_abort ("%s:%u: runtime error: lower bound %zd must be >= %zd\n",
+                 filename, lineno, index, lower_bound);
+}
+
+/* Upper bound failure.  */
+
+void
+_libga68_upper_bound (const char *filename, unsigned int lineno,
+                          ssize_t index, ssize_t upper_bound)
+{
+  _libga68_abort ("%s:%u: runtime error: upper bound %zd must be <= %zd\n",
+                 filename, lineno, index, upper_bound);
+}
+
+/* Bounds failure.  */
+
+void
+_libga68_bounds (const char *filename, unsigned int lineno,
+                ssize_t index, ssize_t lower_bound, ssize_t upper_bound)
+{
+  _libga68_abort ("%s:%u: runtime error: bound %zd out of range [%zd:%zd]\n",
+                 filename, lineno, index, lower_bound, upper_bound);
+}
+
+/* Dimension failure.  */
+
+void
+_libga68_dim (const char *filename, unsigned int lineno,
+             size_t dim, size_t index)
+{
+  _libga68_abort ("%s:%u: runtime error: invalid dimension %zd; shall be > 0 
and <= %zu\n",
+                 filename, lineno, index, dim);
+}
+
+/* Multiples have different bounds in assignations.  */
+
+void
+_libga68_bounds_mismatch (const char *filename, unsigned int lineno,
+                         size_t dim, ssize_t lb1, ssize_t ub1,
+                         ssize_t lb2, ssize_t ub2)
+{
+  _libga68_abort ("%s:%u: runtime error: multiple bounds mismatch in \
+assignation: dim %zu: [%zd:%zd] /= [%zd:%zd]\n",
+                 filename, lineno, dim, lb1, ub1, lb2, ub2);
+}
diff --git a/libga68/ga68-posix.c b/libga68/ga68-posix.c
new file mode 100644
index 00000000000..cd8104cdc51
--- /dev/null
+++ b/libga68/ga68-posix.c
@@ -0,0 +1,403 @@
+/* Support run-time routines for the POSIX prelude.
+
+   Copyright (C) 2025 Jose E. Marchesi.
+
+   GCC is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   GCC 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 General Public License for more
+   details.
+
+   Under Section 7 of GPL version 3, you are granted additional permissions
+   described in the GCC Runtime Library Exception, version 3.1, as published by
+   the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and a copy
+   of the GCC Runtime Library Exception along with this program; see the files
+   COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>  /* For open.  */
+#include <unistd.h> /* For close and write.  */
+#include <errno.h>  /* For errno.  */
+#include <sys/socket.h>
+#include <sys/stat.h> /* For struct stat */
+#include <netinet/in.h>
+#include <netdb.h> /* For gethostbyname.  */
+#include <limits.h> /* For LLONG_MAX */
+
+#include "ga68.h"
+
+/* Some Unicode code points used in this file.  */
+
+#define REPLACEMENT_CHARACTER 0xFFFD
+#define NEWLINE 0x000A
+
+/* Errno.  */
+
+static int _libga68_errno;
+
+/* Simple I/O based on POSIX file descriptors.  */
+
+int
+_libga68_posixerrno (void)
+{
+  return _libga68_errno;
+}
+
+void
+_libga68_posixperror (uint32_t *s, size_t len, size_t stride)
+{
+  size_t u8len;
+  uint8_t *u8str = _libga68_u32_to_u8 (s, len, stride, NULL, &u8len);
+
+  const char *errstr = strerror (_libga68_errno);
+  (void) write (2, u8str, u8len);
+  (void) write (2, ": ", 2);
+  (void) write (2, errstr, strlen (errstr));
+  (void) write (2, "\n", 1);
+}
+
+uint32_t *
+_libga68_posixstrerror (int errnum, size_t *len)
+{
+  const char *str = strerror (errnum);
+  return _libga68_u8_to_u32 ((const uint8_t *)str, strlen (str), NULL, len);
+}
+
+#define FILE_O_DEFAULT 0x0
+#define FILE_O_RDONLY  0x1
+#define FILE_O_WRONLY  0x2
+#define FILE_O_RDWR    0x3
+#define FILE_O_TRUNC   0x4
+
+int
+_libga68_posixfopen (uint32_t *pathname, size_t len, size_t stride,
+                    unsigned int flags)
+{
+  int openflags = 0;
+  size_t u8len;
+  uint8_t *u8pathname = _libga68_u32_to_u8 (pathname, len, stride, NULL, 
&u8len);
+
+  if (flags & FILE_O_RDONLY)
+    openflags |= O_RDONLY;
+  if (flags & FILE_O_WRONLY)
+    openflags |= O_WRONLY;
+  if (flags & FILE_O_RDWR)
+    openflags |= O_RDWR;
+  if (flags & FILE_O_TRUNC)
+    openflags |= O_TRUNC;
+
+  char *filepath = _libga68_malloc_internal (u8len + 1);
+  memcpy (filepath, u8pathname, u8len);
+  filepath[u8len] = '\0';
+  int fd = open (filepath, openflags);
+  _libga68_errno = errno;
+  _libga68_free_internal (filepath);
+  return fd;
+}
+
+int
+_libga68_posixcreat (uint32_t *pathname, size_t len, size_t stride,
+                    uint32_t mode)
+{
+  size_t u8len;
+  uint8_t *u8pathname = _libga68_u32_to_u8 (pathname, len, stride, NULL, 
&u8len);
+  u8pathname[u8len] = '\0';
+
+  int res = creat (u8pathname, mode);
+  _libga68_errno = errno;
+  return res;
+}
+
+int
+_libga68_posixclose (int fd)
+{
+  int res = close (fd);
+  _libga68_errno = errno;
+  return res;
+}
+
+/* Implementation of the posix prelude `posix argc'.  */
+
+int
+_libga68_posixargc (void)
+{
+  return _libga68_argc;
+}
+
+/* Implementation of the posix prelude `posix argv'.  */
+
+uint32_t *
+_libga68_posixargv (int n, size_t *len)
+{
+  if (n < 0 || n > _libga68_argc)
+    {
+      /* Return an empty string.  */
+      *len = 0;
+      return NULL;
+    }
+  else
+    {
+      char *arg = _libga68_argv[n - 1];
+      return _libga68_u8_to_u32 (arg, strlen (arg), NULL, len);
+    }
+}
+
+/* Implementation of the posix prelude `posix getenv'.  */
+
+void
+_libga68_posixgetenv (uint32_t *s, size_t len, size_t stride,
+                     uint32_t **r, size_t *rlen)
+{
+  size_t varlen;
+  char *varname = _libga68_u32_to_u8 (s, len, stride, NULL, &varlen);
+
+  char *var = _libga68_malloc_internal (varlen + 1);
+  memcpy (var, varname, varlen);
+  var[varlen] = '\0';
+  char *val = getenv (var);
+  _libga68_free_internal (var);
+
+  if (val == NULL)
+    {
+      /* Return an empty string.  */
+      *r = NULL;
+      *rlen = 0;
+    }
+  else
+    *r = _libga68_u8_to_u32 (val, strlen (val), NULL, rlen);
+}
+
+/* Implementation of the posix prelude `posix puts'.  */
+
+void
+_libga68_posixputs (uint32_t *s, size_t len, size_t stride)
+{
+  (void) _libga68_posixfputs (1, s, len, stride);
+}
+
+/* Implementation of the posix prelude `posix fputs'.  */
+
+int
+_libga68_posixfputs (int fd, uint32_t *s, size_t len, size_t stride)
+{
+  size_t u8len;
+  uint8_t *u8str = _libga68_u32_to_u8 (s, len, stride, NULL, &u8len);
+
+  ssize_t ret = write (fd, u8str, u8len);
+  _libga68_errno = errno;
+  if (ret == -1)
+    return 0;
+  else
+    return u8len;
+}
+
+/* Implementation of the posix prelude `posix putc'.  */
+
+uint32_t
+_libga68_posixfputc (int fd, uint32_t c)
+{
+  uint8_t u8[6];
+
+  int u8len = _libga68_u8_uctomb (u8, c, 6);
+  if (u8len < 0)
+    return REPLACEMENT_CHARACTER;
+
+  ssize_t ret = write (fd, &u8, u8len);
+  if (ret == -1)
+    return REPLACEMENT_CHARACTER;
+  else
+    return c;
+}
+
+/* Implementation of the posix prelude `posix putchar'.  */
+
+uint32_t
+_libga68_posixputchar (uint32_t c)
+{
+  return _libga68_posixfputc (1, c);
+}
+
+/* Implementation of the posix prelude `posix fgetc'.  */
+
+uint32_t
+_libga68_posixfgetc (int fd)
+{
+  /* We need to read one char (byte) at a time from FD, until we complete a
+     full Unicode character.  Then we convert to UCS-4.  */
+
+  uint8_t c;
+  uint8_t u8c[6];
+  size_t morechars = 0;
+  size_t i;
+
+  /* Read first UTF-8 character.  This gives us the total length of the
+     character.  */
+  if (read (fd, &c, 1) != 1)
+    return REPLACEMENT_CHARACTER;
+
+  if (c < 128)
+    morechars = 0;
+  else if (c < 224)
+    morechars = 1;
+  else if (c < 240)
+    morechars = 2;
+  else
+    morechars = 3;
+
+  u8c[0] = c;
+  for (i = 0; i < morechars; ++i)
+    {
+      if (read (fd, &c, 1) != 1)
+       return REPLACEMENT_CHARACTER;
+      u8c[i + 1] = c;
+    }
+
+  uint32_t res;
+  int length = _libga68_u8_mbtouc (&res, (const uint8_t *) &u8c, 1);
+  if (res == REPLACEMENT_CHARACTER || length != 1)
+    return REPLACEMENT_CHARACTER;
+  else
+    return res;
+}
+
+/* Implementation of the posix prelude `posix getchar'.  */
+
+uint32_t
+_libga68_posixgetchar (void)
+{
+  return _libga68_posixfgetc (0);
+}
+
+/* Implementation of the posix prelude `posix fgets'.  */
+
+uint32_t *
+_libga68_posixfgets (int fd, int nchars, size_t *len)
+{
+  uint32_t *res = NULL;
+  int n = 0;
+  uint32_t uc;
+
+  if (nchars > 0)
+    {
+      /* Read exactly nchar or until EOF.  */
+      res = _libga68_malloc (nchars * sizeof (uint32_t));
+      do
+       {
+         uc = _libga68_posixfgetc (fd);
+         if (uc == REPLACEMENT_CHARACTER)
+           break;
+         res[n++] = uc;
+       }
+      while (n < nchars);
+    }
+  else
+    {
+      /* Read until newline or EOF.  */
+      size_t allocated = 80 * sizeof (uint32_t);
+      res = _libga68_malloc (allocated);
+      do
+       {
+         uc = _libga68_posixfgetc (fd);
+         if (uc != REPLACEMENT_CHARACTER)
+           {
+             if (n % 80 == 0)
+               res = _libga68_realloc (res, n * 80 * sizeof (uint32_t) + 80 * 
sizeof (uint32_t));
+             res[n++] = uc;
+           }
+       }
+      while (uc != NEWLINE && uc != REPLACEMENT_CHARACTER);
+      if (n > 0)
+       res = _libga68_realloc (res, n * 80 * sizeof (uint32_t));
+    }
+
+  *len = n;
+  return res;
+}
+
+/* Implementation of the posix prelude `posix gets'.  */
+
+uint32_t *
+_libga68_posixgets (int nchars, size_t *len)
+{
+  return _libga68_posixfgets (0, nchars, len);
+}
+
+/* Implementation of the posix prelude `fconnect'.  */
+
+int
+_libga68_posixfconnect (uint32_t *str, size_t len, size_t stride,
+                       int port)
+{
+  size_t u8len;
+  uint8_t *u8host = _libga68_u32_to_u8 (str, len, stride, NULL, &u8len);
+
+  /* Create a stream socket.  */
+  int fd = socket (AF_INET, SOCK_STREAM, 0);
+  _libga68_errno = errno;
+  if (fd < 0)
+    goto error;
+
+  /* Lookup the specified host.  */
+  char *host = _libga68_malloc_internal (u8len + 1);
+  memcpy (host, u8host, u8len);
+  host[u8len] = '\0';
+  struct hostent *server = gethostbyname (host);
+  if (server == NULL)
+    {
+      _libga68_errno = h_errno;
+      goto close_fd_and_error;
+    }
+
+  /* Connect the socket to the server.  */
+  struct sockaddr_in serv_addr;
+  memset (&serv_addr, 0, sizeof (serv_addr));
+  serv_addr.sin_family = AF_INET;
+  serv_addr.sin_port = htons (port);
+  memcpy (&serv_addr.sin_addr.s_addr,
+         server->h_addr,
+         server->h_length);
+  int res = connect (fd, (struct sockaddr *) &serv_addr,
+                    sizeof (serv_addr));
+  _libga68_errno = errno;
+  if (res == -1)
+    goto close_fd_and_error;
+
+  _libga68_free_internal (host);
+  return fd;
+
+ close_fd_and_error:
+  close (fd);
+ error:
+  _libga68_free_internal (host);
+  return -1;
+}
+
+/* Implementation of the posix prelude `fsize'.  */
+
+long long int
+_libga68_posixfsize (int fd)
+{
+  struct stat stat;
+
+  if (fstat (fd, &stat) == -1)
+    {
+      _libga68_errno = errno;
+      return -1;
+    }
+
+  if (stat.st_size > LLONG_MAX)
+    {
+      _libga68_errno = EOVERFLOW;
+      return -1;
+    }
+
+  return (long int) stat.st_size;
+}
diff --git a/libga68/ga68-standenv.c b/libga68/ga68-standenv.c
new file mode 100644
index 00000000000..2c1b7979af1
--- /dev/null
+++ b/libga68/ga68-standenv.c
@@ -0,0 +1,48 @@
+/* Support run-time routines for the standard prelude.
+
+   Copyright (C) 2025 Jose E. Marchesi.
+
+   GCC is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   GCC 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 General Public License for more
+   details.
+
+   Under Section 7 of GPL version 3, you are granted additional permissions
+   described in the GCC Runtime Library Exception, version 3.1, as published by
+   the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and a copy
+   of the GCC Runtime Library Exception along with this program; see the files
+   COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h> /* For rand.  */
+
+#include "ga68.h"
+
+/* Implementation of the standard prelude `random' function.  */
+
+float
+_libga68_random (void)
+{
+  float res = (float) rand () / (float) (RAND_MAX);
+  return res;
+}
+
+double
+_libga68_longrandom (void)
+{
+  double res = (double) rand () / (float) (RAND_MAX);
+  return res;
+}
+
+long double
+_libga68_longlongrandom (void)
+{
+  long double res = (long double) rand () / (float) (RAND_MAX);
+  return res;
+}
diff --git a/libga68/ga68-unistr.c b/libga68/ga68-unistr.c
new file mode 100644
index 00000000000..7f2cb97de70
--- /dev/null
+++ b/libga68/ga68-unistr.c
@@ -0,0 +1,615 @@
+/* libga68 unicode support routines.
+   Copyright (C) 2009-2025 Free Software Foundation, Inc.
+   Copyright (C) 2025 Jose E. Marchesi.
+
+   GCC is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   GCC 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 General Public License for more
+   details.
+
+   Under Section 7 of GPL version 3, you are granted additional permissions
+   described in the GCC Runtime Library Exception, version 3.1, as published by
+   the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and a copy
+   of the GCC Runtime Library Exception along with this program; see the files
+   COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* The code in this file has been copied from the unistr gnulib module, written
+   by Bruno Haible, and adapted to support strides.  */
+
+#include <stddef.h> /* For ptrdiff_t */
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+
+#include "ga68.h"
+
+/* CMP (n1, n2) performs a three-valued comparison on n1 vs. n2, where
+   n1 and n2 are expressions without side effects, that evaluate to real
+   numbers (excluding NaN).
+   It returns
+     1  if n1 > n2
+     0  if n1 == n2
+     -1 if n1 < n2
+   The naïve code   (n1 > n2 ? 1 : n1 < n2 ? -1 : 0)  produces a conditional
+   jump with nearly all GCC versions up to GCC 10.
+   This variant     (n1 < n2 ? -1 : n1 > n2)  produces a conditional with many
+   GCC versions up to GCC 9.
+   The better code  (n1 > n2) - (n1 < n2)  from Hacker's Delight § 2-9
+   avoids conditional jumps in all GCC versions >= 3.4.  */
+
+#define CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2)))
+
+/* MIN(a,b) returns the minimum of A and B.  */
+
+#ifndef MIN
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* Compare two UCS-4 strings of same lenght, lexicographically.
+   Return -1, 0 or 1.  */
+
+int
+_libga68_u32_cmp (const uint32_t *s1, size_t stride1,
+                 const uint32_t *s2, size_t stride2,
+                 size_t n)
+{
+  stride1 = stride1 / sizeof (uint32_t);
+  stride2 = stride2 / sizeof (uint32_t);
+  
+  for (; n > 0;)
+    {
+      uint32_t uc1 = *s1;
+      s1 += stride1;
+      uint32_t uc2 = *s2;
+      s2 += stride2;
+      if (uc1 == uc2)
+        {
+          n--;
+          continue;
+        }
+      /* Note that uc1 and uc2 each have at most 31 bits. */
+      return (int)uc1 - (int)uc2;
+      /* > 0 if uc1 > uc2, < 0 if uc1 < uc2. */
+    }
+  return 0;
+}
+
+/* Compare two UCS-4 strings of perhaps different lenghts, lexicographically.
+   Return -1, 0 or 1.  */
+
+int
+_libga68_u32_cmp2 (const uint32_t *s1, size_t n1, size_t stride1,
+                  const uint32_t *s2, size_t n2, size_t stride2)
+{
+  int cmp = _libga68_u32_cmp (s1, stride1, s2, stride2, MIN (n1, n2));
+
+  if (cmp == 0)
+    cmp = CMP (n1, n2);
+
+  return cmp;
+}
+
+/* Get the UCS code for the first character of a given UTF-8 string.  */
+
+int
+_libga68_u8_mbtouc (uint32_t *puc, const uint8_t *s, size_t n)
+{
+  uint8_t c = *s;
+
+  if (c < 0x80)
+    {
+      *puc = c;
+      return 1;
+    }
+  else if (c >= 0xc2)
+    {
+      if (c < 0xe0)
+        {
+          if (n >= 2)
+            {
+              if ((s[1] ^ 0x80) < 0x40)
+                {
+                  *puc = ((unsigned int) (c & 0x1f) << 6)
+                         | (unsigned int) (s[1] ^ 0x80);
+                  return 2;
+                }
+              /* invalid multibyte character */
+            }
+          else
+            {
+              /* incomplete multibyte character */
+              *puc = 0xfffd;
+              return 1;
+            }
+        }
+      else if (c < 0xf0)
+        {
+          if (n >= 3)
+            {
+              if ((s[1] ^ 0x80) < 0x40
+                  && (c >= 0xe1 || s[1] >= 0xa0)
+                  && (c != 0xed || s[1] < 0xa0))
+                {
+                  if ((s[2] ^ 0x80) < 0x40)
+                    {
+                      *puc = ((unsigned int) (c & 0x0f) << 12)
+                             | ((unsigned int) (s[1] ^ 0x80) << 6)
+                             | (unsigned int) (s[2] ^ 0x80);
+                      return 3;
+                    }
+                  /* invalid multibyte character */
+                  *puc = 0xfffd;
+                  return 2;
+                }
+              /* invalid multibyte character */
+              *puc = 0xfffd;
+              return 1;
+            }
+          else
+            {
+              *puc = 0xfffd;
+              if (n == 1)
+                {
+                  /* incomplete multibyte character */
+                  return 1;
+                }
+              else
+                {
+                  if ((s[1] ^ 0x80) < 0x40
+                      && (c >= 0xe1 || s[1] >= 0xa0)
+                      && (c != 0xed || s[1] < 0xa0))
+                    {
+                      /* incomplete multibyte character */
+                      return 2;
+                    }
+                  else
+                    {
+                      /* invalid multibyte character */
+                      return 1;
+                    }
+                }
+            }
+        }
+      else if (c <= 0xf4)
+        {
+          if (n >= 4)
+            {
+              if ((s[1] ^ 0x80) < 0x40
+                  && (c >= 0xf1 || s[1] >= 0x90)
+                  && (c < 0xf4 || (/* c == 0xf4 && */ s[1] < 0x90)))
+                {
+                  if ((s[2] ^ 0x80) < 0x40)
+                    {
+                      if ((s[3] ^ 0x80) < 0x40)
+                        {
+                          *puc = ((unsigned int) (c & 0x07) << 18)
+                                 | ((unsigned int) (s[1] ^ 0x80) << 12)
+                                 | ((unsigned int) (s[2] ^ 0x80) << 6)
+                                 | (unsigned int) (s[3] ^ 0x80);
+                          return 4;
+                        }
+                      /* invalid multibyte character */
+                      *puc = 0xfffd;
+                      return 3;
+                    }
+                  /* invalid multibyte character */
+                  *puc = 0xfffd;
+                  return 2;
+                }
+              /* invalid multibyte character */
+              *puc = 0xfffd;
+              return 1;
+            }
+          else
+            {
+              *puc = 0xfffd;
+              if (n == 1)
+                {
+                  /* incomplete multibyte character */
+                  return 1;
+                }
+              else
+                {
+                  if ((s[1] ^ 0x80) < 0x40
+                      && (c >= 0xf1 || s[1] >= 0x90)
+                      && (c < 0xf4 || (/* c == 0xf4 && */ s[1] < 0x90)))
+                    {
+                      if (n == 2)
+                        {
+                          /* incomplete multibyte character */
+                          return 2;
+                        }
+                      else
+                        {
+                          if ((s[2] ^ 0x80) < 0x40)
+                            {
+                              /* incomplete multibyte character */
+                              return 3;
+                            }
+                          else
+                            {
+                              /* invalid multibyte character */
+                              return 2;
+                            }
+                        }
+                    }
+                  else
+                    {
+                      /* invalid multibyte character */
+                      return 1;
+                    }
+                }
+            }
+        }
+    }
+  /* invalid multibyte character */
+  *puc = 0xfffd;
+  return 1;
+}
+
+/* Encode a given UCS code in UTF-8.  */
+
+int
+_libga68_u8_uctomb (uint8_t *s, uint32_t uc, ptrdiff_t n)
+{
+  if (uc < 0x80)
+    {
+      if (n > 0)
+        {
+          s[0] = uc;
+          return 1;
+        }
+      /* else return -2, below.  */
+    }
+  else
+    {
+      int count;
+
+      if (uc < 0x800)
+        count = 2;
+      else if (uc < 0x10000)
+        {
+          if (uc < 0xd800 || uc >= 0xe000)
+            count = 3;
+          else
+            return -1;
+        }
+      else if (uc < 0x110000)
+        count = 4;
+      else
+        return -1;
+
+      if (n >= count)
+        {
+          switch (count) /* note: code falls through cases! */
+            {
+            case 4: s[3] = 0x80 | (uc & 0x3f); uc = uc >> 6; uc |= 0x10000;
+              /* Fallthrough.  */
+            case 3: s[2] = 0x80 | (uc & 0x3f); uc = uc >> 6; uc |= 0x800;
+             /* Fallthrough.  */
+            case 2: s[1] = 0x80 | (uc & 0x3f); uc = uc >> 6; uc |= 0xc0;
+          /*case 1:*/ s[0] = uc;
+            }
+          return count;
+        }
+    }
+  return -2;
+}
+
+/* Convert UCS-4 to UTF-8  */
+
+uint8_t *
+_libga68_u32_to_u8 (const uint32_t *s, size_t n, size_t stride,
+                   uint8_t *resultbuf, size_t *lengthp)
+{
+  const uint32_t *s_end;
+  /* Output string accumulator.  */
+  uint8_t *result;
+  size_t allocated;
+  size_t length;
+
+  stride = stride / sizeof (uint32_t);
+  s_end = s + (n * stride);
+  
+  if (resultbuf != NULL)
+    {
+      result = resultbuf;
+      allocated = *lengthp;
+    }
+  else
+    {
+      result = NULL;
+      allocated = 0;
+    }
+  length = 0;
+  /* Invariants:
+     result is either == resultbuf or == NULL or malloc-allocated.
+     If length > 0, then result != NULL.  */
+
+  while (s < s_end)
+    {
+      uint32_t uc;
+      int count;
+
+      /* Fetch a Unicode character from the input string.  */
+      uc = *s;
+      s += stride;
+      /* No need to call the safe variant u32_mbtouc, because
+         u8_uctomb will verify uc anyway.  */
+
+      /* Store it in the output string.  */
+      count = _libga68_u8_uctomb (result + length, uc, allocated - length);
+      if (count == -1)
+        {
+          if (!(result == resultbuf || result == NULL))
+            free (result);
+          errno = EILSEQ;
+          return NULL;
+        }
+      if (count == -2)
+        {
+          uint8_t *memory;
+
+          allocated = (allocated > 0 ? 2 * allocated : 12);
+          if (length + 6 > allocated)
+            allocated = length + 6;
+          if (result == resultbuf || result == NULL)
+           memory = (uint8_t *) _libga68_malloc (allocated * sizeof (uint8_t));
+          else
+           memory =
+             (uint8_t *) _libga68_realloc (result, allocated * sizeof 
(uint8_t));
+
+          if (result == resultbuf && length > 0)
+            memcpy ((char *) memory, (char *) result,
+                    length * sizeof (uint8_t));
+          result = memory;
+          count = _libga68_u8_uctomb (result + length, uc, allocated - length);
+          if (count < 0)
+            abort ();
+        }
+      length += count;
+    }
+
+  if (length == 0)
+    {
+      if (result == NULL)
+        {
+          /* Return a non-NULL value.  NULL means error.  */
+          result = (uint8_t *) _libga68_malloc (1);
+          if (result == NULL)
+            {
+              errno = ENOMEM;
+              return NULL;
+            }
+        }
+    }
+  else if (result != resultbuf && length < allocated)
+    {
+      /* Shrink the allocated memory if possible.  */
+      uint8_t *memory;
+
+      memory = (uint8_t *) _libga68_realloc_unchecked (result, length * sizeof 
(uint8_t));
+      if (memory != NULL)
+        result = memory;
+    }
+
+  *lengthp = length;
+  return result;
+}
+
+/* Used by ga68_u8_to_u32 below.  */
+
+static int
+_libga68_u8_mbtoucr (uint32_t *puc, const uint8_t *s, size_t n)
+{
+  uint8_t c = *s;
+
+  if (c < 0x80)
+    {
+      *puc = c;
+      return 1;
+    }
+  else if (c >= 0xc2)
+    {
+      if (c < 0xe0)
+        {
+          if (n >= 2)
+            {
+              if ((s[1] ^ 0x80) < 0x40)
+                {
+                  *puc = ((unsigned int) (c & 0x1f) << 6)
+                         | (unsigned int) (s[1] ^ 0x80);
+                  return 2;
+                }
+              /* invalid multibyte character */
+            }
+          else
+            {
+              /* incomplete multibyte character */
+              *puc = 0xfffd;
+              return -2;
+            }
+        }
+      else if (c < 0xf0)
+        {
+          if (n >= 2)
+            {
+              if ((s[1] ^ 0x80) < 0x40
+                  && (c >= 0xe1 || s[1] >= 0xa0)
+                  && (c != 0xed || s[1] < 0xa0))
+                {
+                  if (n >= 3)
+                    {
+                      if ((s[2] ^ 0x80) < 0x40)
+                        {
+                          *puc = ((unsigned int) (c & 0x0f) << 12)
+                                 | ((unsigned int) (s[1] ^ 0x80) << 6)
+                                 | (unsigned int) (s[2] ^ 0x80);
+                          return 3;
+                        }
+                      /* invalid multibyte character */
+                    }
+                  else
+                    {
+                      /* incomplete multibyte character */
+                      *puc = 0xfffd;
+                      return -2;
+                    }
+                }
+              /* invalid multibyte character */
+            }
+          else
+            {
+              /* incomplete multibyte character */
+              *puc = 0xfffd;
+              return -2;
+            }
+        }
+      else if (c <= 0xf4)
+        {
+          if (n >= 2)
+            {
+              if ((s[1] ^ 0x80) < 0x40
+                  && (c >= 0xf1 || s[1] >= 0x90)
+                  && (c < 0xf4 || (/* c == 0xf4 && */ s[1] < 0x90)))
+                {
+                  if (n >= 3)
+                    {
+                      if ((s[2] ^ 0x80) < 0x40)
+                        {
+                          if (n >= 4)
+                            {
+                              if ((s[3] ^ 0x80) < 0x40)
+                                {
+                                  *puc = ((unsigned int) (c & 0x07) << 18)
+                                         | ((unsigned int) (s[1] ^ 0x80) << 12)
+                                         | ((unsigned int) (s[2] ^ 0x80) << 6)
+                                         | (unsigned int) (s[3] ^ 0x80);
+                                  return 4;
+                                }
+                              /* invalid multibyte character */
+                            }
+                          else
+                            {
+                              /* incomplete multibyte character */
+                              *puc = 0xfffd;
+                              return -2;
+                            }
+                        }
+                      /* invalid multibyte character */
+                    }
+                  else
+                    {
+                      /* incomplete multibyte character */
+                      *puc = 0xfffd;
+                      return -2;
+                    }
+                }
+              /* invalid multibyte character */
+            }
+          else
+            {
+              /* incomplete multibyte character */
+              *puc = 0xfffd;
+              return -2;
+            }
+        }
+    }
+  /* invalid multibyte character */
+  *puc = 0xfffd;
+  return -1;
+}
+
+/* Convert UTF-8 to UTF-32/UCS-4  */
+
+uint32_t *
+_libga68_u8_to_u32 (const uint8_t *s, size_t n, uint32_t *resultbuf, size_t 
*lengthp)
+{
+  const uint8_t *s_end = s + n;
+  /* Output string accumulator.  */
+  uint32_t *result;
+  size_t allocated;
+  size_t length;
+
+  if (resultbuf != NULL)
+    {
+      result = resultbuf;
+      allocated = *lengthp;
+    }
+  else
+    {
+      result = NULL;
+      allocated = 0;
+    }
+  length = 0;
+  /* Invariants:
+     result is either == resultbuf or == NULL or malloc-allocated.
+     If length > 0, then result != NULL.  */
+
+  while (s < s_end)
+    {
+      uint32_t uc;
+      int count;
+
+      /* Fetch a Unicode character from the input string.  */
+      count = _libga68_u8_mbtoucr (&uc, s, s_end - s);
+      if (count < 0)
+        {
+          if (!(result == resultbuf || result == NULL))
+            free (result);
+          errno = EILSEQ;
+          return NULL;
+        }
+      s += count;
+
+      /* Store it in the output string.  */
+      if (length + 1 > allocated)
+        {
+          uint32_t *memory;
+
+          allocated = (allocated > 0 ? 2 * allocated : 12);
+          if (length + 1 > allocated)
+            allocated = length + 1;
+          if (result == resultbuf || result == NULL)
+           memory = (uint32_t *) _libga68_malloc (allocated * sizeof 
(uint32_t));
+          else
+           memory =
+             (uint32_t *) _libga68_realloc (result, allocated * sizeof 
(uint32_t));
+
+          if (result == resultbuf && length > 0)
+            memcpy ((char *) memory, (char *) result,
+                    length * sizeof (uint32_t));
+          result = memory;
+        }
+      result[length++] = uc;
+    }
+
+  if (length == 0)
+    {
+      if (result == NULL)
+        {
+          /* Return a non-NULL value.  NULL means error.  */
+          result = (uint32_t *) _libga68_malloc (1);
+        }
+    }
+  else if (result != resultbuf && length < allocated)
+    {
+      /* Shrink the allocated memory if possible.  */
+      uint32_t *memory;
+
+      memory = (uint32_t *) _libga68_realloc_unchecked (result, length * 
sizeof (uint32_t));
+      if (memory != NULL)
+        result = memory;
+    }
+
+  *lengthp = length;
+  return result;
+}
diff --git a/libga68/ga68.h b/libga68/ga68.h
new file mode 100644
index 00000000000..4149d81c484
--- /dev/null
+++ b/libga68/ga68.h
@@ -0,0 +1,122 @@
+/* Definitions for libga68.
+   Copyright (C) 2025 Jose E. Marchesi.
+
+   GCC is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   GCC 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 General Public License for more
+   details.
+
+   Under Section 7 of GPL version 3, you are granted additional permissions
+   described in the GCC Runtime Library Exception, version 3.1, as published by
+   the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and a copy
+   of the GCC Runtime Library Exception along with this program; see the files
+   COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef GA68_H
+#define GA68_H
+
+#include <stddef.h> /* For size_t.  */
+#include <stdint.h>
+#include <stdarg.h>
+#ifdef __has_include
+# if __has_include (<sys/types.h>)
+#  include <sys/types.h> /* For ssize_t.  */
+# endif
+#endif
+
+/* ga68-error.c  */
+
+void _libga68_abort (const char *fmt, ...)
+  __attribute__ ((__format__ (__printf__, 1, 2), __nonnull__ (1),
+                 __noreturn__));
+
+void _libga68_assert (const char *filename, unsigned int lineno);
+void _libga68_derefnil (const char *filename, unsigned int lineno);
+void _libga68_invalidcharerror (const char *filename, unsigned int lineno,
+                               int c);
+
+void _libga68_bitsboundserror (const char *filename, unsigned int lineno,
+                              ssize_t pos);
+void _libga68_unreachable (const char *filename, unsigned int lineno);
+void _libga68_lower_bound (const char *filename, unsigned int lineno,
+                          ssize_t index, ssize_t lower_bound);
+void _libga68_upper_bound (const char *filename, unsigned int lineno,
+                          ssize_t index, ssize_t upper_bound);
+void _libga68_bounds (const char *filename, unsigned int lineno,
+                     ssize_t index, ssize_t lower_bound, ssize_t upper_bound);
+void _libga68_dim (const char *filename, unsigned int lineno,
+                  size_t dim, size_t index);
+void _libga68_bounds_mismatch (const char *filename, unsigned int lineno,
+                              size_t dim, ssize_t lb1, ssize_t ub1,
+                              ssize_t lb2, ssize_t ub2);
+
+/* ga68-alloc.c  */
+
+void _libga68_init_heap (void);
+void *_libga68_malloc (size_t size);
+void *_libga68_malloc_internal (size_t size);
+void *_libga68_realloc (void *ptr, size_t size);
+void *_libga68_realloc_unchecked (void *ptr, size_t size);
+void _libga68_free_internal (void *ptr);
+
+/* ga68-standenv.c  */
+
+float _libga68_random (void);
+double _libga68_longrandom (void);
+long double _libga68_longlongrandom (void);
+
+/* ga68-posix.c  */
+
+int _libga68_posixerrno (void);
+void _libga68_posixperror (uint32_t *s, size_t len, size_t stride);
+uint32_t *_libga68_posixstrerror (int errnum, size_t *len);
+long long int _libga68_posixfsize (int fd);
+int _libga68_posixfopen (uint32_t *pathname, size_t len, size_t stride, 
unsigned int flags);
+int _libga68_posixcreat (uint32_t *pathname, size_t len, size_t stride, 
uint32_t mode);
+int _libga68_posixclose (int fd);
+int _libga68_posixargc (void);
+uint32_t *_libga68_posixargv (int n, size_t *len);
+void _libga68_posixgetenv (uint32_t *s, size_t len, size_t stride,
+                          uint32_t **r, size_t *rlen);
+void _libga68_posixputs (uint32_t *s, size_t len, size_t stride);
+uint32_t _libga68_posixputchar (uint32_t c);
+uint32_t _libga68_posixfputc (int fd, uint32_t c);
+int _libga68_posixfputs (int fd, uint32_t *s, size_t len, size_t stride);
+
+uint32_t _libga68_posixgetchar (void);
+uint32_t _libga68_posixfgetc (int fd);
+uint32_t *_libga68_posixfgets (int fd, int nchars, size_t *len);
+uint32_t *_libga68_posixgets (int nchars, size_t *len);
+
+int _libga68_posixfconnect (uint32_t *str, size_t len, size_t stride,
+                           int port);
+
+/* ga68-unistr.c  */
+
+int _libga68_u32_cmp (const uint32_t *s1, size_t stride1,
+                     const uint32_t *s2, size_t stride2,
+                     size_t n);
+int _libga68_u32_cmp2 (const uint32_t *s1, size_t n1, size_t stride1,
+                      const uint32_t *s2, size_t n2, size_t stride2);
+int _libga68_u8_uctomb (uint8_t *s, uint32_t uc, ptrdiff_t n);
+int _libga68_u8_mbtouc (uint32_t *puc, const uint8_t *s, size_t n);
+uint8_t *_libga68_u32_to_u8 (const uint32_t *s, size_t n, size_t stride,
+                            uint8_t *resultbuf, size_t *lengthp);
+uint32_t *_libga68_u8_to_u32 (const uint8_t *s, size_t n,
+                             uint32_t *resultbuf, size_t *lengthp);
+
+/* libga68.c  */
+
+extern int _libga68_argc;
+extern char **_libga68_argv;
+
+void _libga68_set_exit_status (int status);
+
+#endif /* ! GA68_H */
diff --git a/libga68/libga68.c b/libga68/libga68.c
new file mode 100644
index 00000000000..60f930a5333
--- /dev/null
+++ b/libga68/libga68.c
@@ -0,0 +1,52 @@
+/* GNU Algol Compiler run-time.
+   Copyright (C) 2025 Jose E. Marchesi.
+
+   GCC is free software; you can redistribute it and/or modify it under the
+   terms of the GNU General Public License as published by the Free Software
+   Foundation; either version 3, or (at your option) any later version.
+
+   GCC 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 General Public License for more
+   details.
+
+   Under Section 7 of GPL version 3, you are granted additional permissions
+   described in the GCC Runtime Library Exception, version 3.1, as published by
+   the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and a copy
+   of the GCC Runtime Library Exception along with this program; see the files
+   COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "ga68.h"
+
+/* argc and argv are preserved in the following objects.  */
+
+int _libga68_argc;
+char **_libga68_argv;
+
+/* Exit status of the program reported to the OS upon exit.  */
+
+static int exit_status;
+
+void
+_libga68_set_exit_status (int status)
+{
+  exit_status = status;
+}
+
+/* Entry point for Algol 68 programs.  */
+
+void __algol68_main (void);
+
+int
+main (int argc, char **argv)
+{
+  _libga68_argc = argc;
+  _libga68_argv = argv;
+
+  _libga68_init_heap ();
+  __algol68_main ();
+  return exit_status;
+}
diff --git a/libga68/libga68.spec.in b/libga68/libga68.spec.in
new file mode 100644
index 00000000000..7b09f655a2b
--- /dev/null
+++ b/libga68/libga68.spec.in
@@ -0,0 +1,11 @@
+#
+# This spec file is read by ga68 when linking.
+# It is used to specify the libraries we need to link in, in the right
+# order.
+#
+
+%rename link linkorig_ga68_renamed
+*link: %(linkorig_ga68_renamed)
+
+%rename lib liborig_ga68_renamed
+*lib: %{noga68lib: ; :@SPEC_LIBGA68_DEPS@} %(liborig_ga68_renamed)
-- 
2.30.2

Reply via email to