| /* Glibc.c provides access to some libc functions. |
| |
| Copyright (C) 2016-2026 Free Software Foundation, Inc. |
| Contributed by Gaius Mulley <gaius@glam.ac.uk>. |
| |
| This file is part of GNU Modula-2. |
| |
| GNU Modula-2 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. |
| |
| GNU Modula-2 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. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Modula-2; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| |
| #if defined(__cplusplus) |
| #define EXTERN extern "C" |
| #else |
| #define EXTERN |
| #endif |
| |
| #undef BUILD_MC_LIBC_TRACE |
| |
| #if defined(BUILD_MC_LIBC_TRACE) |
| static bool initialzed_trace = false; |
| static bool trace_on = false; |
| |
| static |
| void |
| check_init (void) |
| { |
| if (! initialzed_trace) |
| { |
| initialzed_trace = true; |
| trace_on = ((getenv ("MC_LIBC_TRACE") != NULL)); |
| } |
| } |
| #endif |
| |
| static |
| void |
| tracedb (const char *format, ...) |
| { |
| #if defined(BUILD_MC_LIBC_TRACE) |
| check_init (); |
| if (trace_on) |
| { |
| va_list arg; |
| va_start (arg, format); |
| { |
| vfprintf (stdout, format, arg); |
| fflush (stdout); |
| } |
| va_end (arg); |
| } |
| #endif |
| } |
| |
| static |
| void |
| tracedb_open (const void *p, int flags, int mode) |
| { |
| #if defined(BUILD_MC_LIBC_TRACE) |
| bool item_written = false; |
| tracedb ("libc_open (%s, flags = 0x%x = ", p, flags); |
| |
| int bits = (flags & O_ACCMODE); |
| tracedb ("bits = 0x%x", bits); |
| if (bits == O_RDONLY) |
| { |
| tracedb ("O_RDONLY"); |
| item_written = true; |
| } |
| if ((flags & O_WRONLY) != 0) |
| { |
| if (item_written) |
| tracedb (" | "); |
| tracedb ("O_WRONLY"); |
| item_written = true; |
| } |
| if ((flags & O_RDWR) != 0) |
| { |
| if (item_written) |
| tracedb (" | "); |
| tracedb ("O_RDWR"); |
| item_written = true; |
| } |
| tracedb (", 0x%x)\n", mode); |
| #endif |
| } |
| |
| static |
| void |
| tracedb_result (int result) |
| { |
| #if defined(BUILD_MC_LIBC_TRACE) |
| tracedb (" result = %d", result); |
| if (result == -1) |
| tracedb (", errno = %s", strerror (errno)); |
| tracedb ("\n"); |
| #endif |
| } |
| |
| static |
| void |
| tracedb_zresult (size_t result) |
| { |
| #if defined(BUILD_MC_LIBC_TRACE) |
| tracedb (" result = %zd", result); |
| if (result == -1) |
| tracedb (", errno = %s", strerror (errno)); |
| tracedb ("\n"); |
| #endif |
| } |
| |
| EXTERN |
| size_t |
| libc_read (int fd, void *a, size_t nbytes) |
| { |
| tracedb ("libc_read (%d, %p, %zd)\n", fd, a, nbytes); |
| size_t result = read (fd, a, nbytes); |
| tracedb_zresult (result); |
| return result; |
| } |
| |
| EXTERN |
| size_t |
| libc_write (int fd, void *a, size_t nbytes) |
| { |
| tracedb ("libc_write (%d, %p, %zd)\n", fd, a, nbytes); |
| size_t result = write (fd, a, nbytes); |
| tracedb_zresult (result); |
| return result; |
| } |
| |
| EXTERN |
| int |
| libc_close (int fd) |
| { |
| tracedb ("libc_close (%d)\n", fd); |
| int result = close (fd); |
| tracedb_result (result); |
| return result; |
| } |
| |
| EXTERN |
| int |
| libc_exit (int code) |
| { |
| exit (code); |
| } |
| |
| EXTERN |
| void |
| libc_perror (const char *s, unsigned int length) |
| { |
| perror (s); |
| } |
| |
| EXTERN |
| int |
| libc_abort () |
| { |
| abort (); |
| } |
| |
| EXTERN |
| size_t |
| libc_strlen (char *s) |
| { |
| return strlen (s); |
| } |
| |
| EXTERN |
| time_t |
| libc_time (time_t *buf) |
| { |
| return time (buf); |
| } |
| |
| EXTERN |
| void * |
| libc_localtime (time_t *epochtime) |
| { |
| return localtime (epochtime); |
| } |
| |
| EXTERN |
| int |
| libc_printf (const char *_format, unsigned int _format_high, ...) |
| { |
| va_list arg; |
| int done; |
| char format[_format_high + 1]; |
| unsigned int i = 0; |
| unsigned int j = 0; |
| const char *c; |
| |
| do |
| { |
| c = index (&const_cast <char *> (_format)[i], '\\'); |
| if (c == NULL) |
| strcpy (&format[j], &_format[i]); |
| else |
| { |
| memcpy (&format[j], &_format[i], (c - _format) - i); |
| i = c - _format; |
| j += c - _format; |
| if (_format[i + 1] == 'n') |
| format[j] = '\n'; |
| else |
| format[j] = _format[i + 1]; |
| j++; |
| i += 2; |
| } |
| } |
| while (c != NULL); |
| |
| va_start (arg, _format_high); |
| done = vfprintf (stdout, format, arg); |
| va_end (arg); |
| return done; |
| } |
| |
| EXTERN |
| int |
| libc_snprintf (void *dest, size_t length, const char *_format, unsigned int _format_high, ...) |
| { |
| va_list arg; |
| int done; |
| char format[_format_high + 1]; |
| unsigned int i = 0; |
| unsigned int j = 0; |
| const char *c; |
| |
| do |
| { |
| c = index (&const_cast <char *> (_format)[i], '\\'); |
| if (c == NULL) |
| strcpy (&format[j], &_format[i]); |
| else |
| { |
| memcpy (&format[j], &_format[i], (c - _format) - i); |
| i = c - _format; |
| j += c - _format; |
| if (_format[i + 1] == 'n') |
| format[j] = '\n'; |
| else |
| format[j] = _format[i + 1]; |
| j++; |
| i += 2; |
| } |
| } |
| while (c != NULL); |
| |
| va_start (arg, _format_high); |
| done = vsnprintf (reinterpret_cast<char *> (dest), length, format, arg); |
| va_end (arg); |
| return done; |
| } |
| |
| EXTERN |
| void * |
| libc_malloc (size_t size) |
| { |
| return malloc (size); |
| } |
| |
| EXTERN |
| void |
| libc_free (void *p) |
| { |
| free (p); |
| } |
| |
| EXTERN |
| char * |
| libc_strcpy (char *dest, char *src) |
| { |
| return strcpy (dest, src); |
| } |
| |
| EXTERN |
| char * |
| libc_strncpy (char *dest, char *src, int n) |
| { |
| return strncpy (dest, src, n); |
| } |
| |
| EXTERN |
| int |
| libc_unlink (char *p) |
| { |
| return unlink (p); |
| } |
| |
| EXTERN |
| int |
| libc_system (char *command) |
| { |
| return system (command); |
| } |
| |
| EXTERN |
| void * |
| libc_memcpy (void *dest, void *src, size_t n) |
| { |
| return memcpy (dest, src, n); |
| } |
| |
| EXTERN |
| char * |
| libc_getenv (char *name) |
| { |
| return getenv (name); |
| } |
| |
| EXTERN |
| int |
| libc_putenv (char *name) |
| { |
| return putenv (name); |
| } |
| |
| EXTERN |
| int |
| libc_creat (char *p, mode_t mode) |
| { |
| tracedb ("libc_creat (%s, 0x%x)\n", p, mode); |
| int result = creat (p, mode); |
| tracedb_result (result); |
| return result; |
| } |
| |
| EXTERN |
| int |
| libc_open (void *p, int flags, int mode) |
| { |
| tracedb_open (p, flags, mode); |
| int result = open (reinterpret_cast <char *> (p), flags, mode); |
| tracedb_result (result); |
| return result; |
| } |
| |
| EXTERN |
| off_t |
| libc_lseek (int fd, off_t offset, int whence) |
| { |
| tracedb ("libc_lseek (%s, %p, %d)\n", fd, offset, whence); |
| off_t result = lseek (fd, offset, whence); |
| tracedb_result (result); |
| return result; |
| } |
| |
| EXTERN |
| void * |
| libc_realloc (void *ptr, size_t size) |
| { |
| return realloc (ptr, size); |
| } |
| |
| EXTERN |
| void * |
| libc_memset (void *s, int c, size_t n) |
| { |
| return memset (s, c, n); |
| } |
| |
| EXTERN |
| void * |
| libc_memmove (void *dest, void *src, size_t n) |
| { |
| return memmove (dest, src, n); |
| } |
| |
| EXTERN |
| int |
| libc_getpid (void) |
| { |
| return getpid (); |
| } |
| |
| EXTERN |
| unsigned int |
| libc_sleep (unsigned int s) |
| { |
| return sleep (s); |
| } |
| |
| EXTERN |
| int |
| libc_atexit (void (*function) (void)) |
| { |
| return atexit (function); |
| } |