| /* A part of the Native C Library for Windows NT |
| Copyright 2007-2015 PC GO Ld. |
| Copyright 2026 Rivoreo |
| |
| This program 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 2 of the License, or (at |
| your option) any later version. |
| |
| This program 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. |
| */ |
| |
| #include <string.h> |
| #include <errno.h> |
| #include <stdio.h> |
| |
| static const char *get_static_error_message(int e) { |
| switch(e) { |
| case 0: return "Success"; |
| case EPERM: return "Operation not permitted"; |
| case ENOENT: return "No such file or directory"; |
| case ESRCH: return "No such process"; |
| case EINTR: return "Interrupted call"; |
| case EIO: return "Input/output error"; |
| case ENXIO: return "Device not configured"; |
| case E2BIG: return "Argument list too long"; |
| case ENOEXEC: return "Exec format error"; |
| case EBADF: return "Bad file descriptor"; |
| case ECHILD: return "No child processes"; |
| case EAGAIN: return "Resource temporarily unavailable"; |
| case ENOMEM: return "Cannot allocate memory"; |
| case EACCES: return "Permission denied"; |
| case EFAULT: return "Bad address"; |
| case EBUSY: return "Device or resource busy"; |
| case EEXIST: return "File exists"; |
| case EXDEV: return "Cross-device link"; |
| case ENODEV: return "No such device"; |
| case ENOTDIR: return "Not a directory"; |
| case EISDIR: return "Is a directory"; |
| case EINVAL: return "Invalid argument"; |
| case ENFILE: return "Too many open files in system"; |
| case EMFILE: return "Too many open files"; |
| case ENOTTY: return "Inappropriate ioctl for device"; |
| case ETXTBSY: return "Text file busy"; |
| case EFBIG: return "File too large"; |
| case ENOSPC: return "No space left on device"; |
| case ESPIPE: return "Illegal seek"; |
| case EROFS: return "Read-only file system"; |
| case EMLINK: return "Too many links"; |
| case EPIPE: return "Broken pipe"; |
| case EDOM: return "Numerical argument out of domain"; |
| case ERANGE: return "Result too large"; |
| case EDEADLK: return "Resource deadlock avoided"; |
| case EINPROGRESS: return "Operation now in progress"; |
| case EALREADY: return "Operation already in progress"; |
| case ENOTSOCK: return "Socket operation on non-socket"; |
| case EDESTADDRREQ: return "Destination address required"; |
| case EMSGSIZE: return "Message too long"; |
| case EPROTOTYPE: return "Protocol wrong type for socket"; |
| case ENOPROTOOPT: return "Protocol not available"; |
| case EPROTONOSUPPORT: return "Protocol not supported"; |
| case ESOCKTNOSUPPORT: return "Socket type not supported"; |
| case EOPNOTSUPP: return "Operation not supported"; |
| case EPFNOSUPPORT: return "Protocol family not supported"; |
| case EADDRINUSE: return "Address already in use"; |
| case EADDRNOTAVAIL: return "Can't assign requested address"; |
| case ENETDOWN: return "Network is down"; |
| case ENETUNREACH: return "Network is unreachable"; |
| case ENETRESET: return "Network dropped connection on reset"; |
| case ECONNABORTED: return "Software caused connection abort"; |
| case ECONNRESET: return "Connection reset by peer"; |
| case ENOBUFS: return "No buffer space available"; |
| case EISCONN: return "Socket is already connected"; |
| case ENOTCONN: return "Socket is not connected"; |
| case ESHUTDOWN: return "Can't send after socket shutdown"; |
| case ETOOMANYREFS: return "Too many references: can't splice"; |
| case ETIMEDOUT: return "Operation timed out"; |
| case ECONNREFUSED: return "Connection refused"; |
| case ELOOP: return "Too many levels of symbolic links"; |
| case ENAMETOOLONG: return "File name too long"; |
| case EHOSTDOWN: return "Host is down"; |
| case EHOSTUNREACH: return "No route to host"; |
| case ENOTEMPTY: return "Directory not empty"; |
| case EPROCLIM: return "Too many processes"; |
| case EUSERS: return "Too many users"; |
| case EDQUOT: return "Disc quota exceeded"; |
| case ESTALE: return "Stale NFS file handle"; |
| case EREMOTE: return "Too many levels of remote in path"; |
| case EBADRPC: return "RPC struct is bad"; |
| case ERPCMISMATCH: return "RPC version wrong"; |
| case EPROGUNAVAIL: return "RPC prog. not avail"; |
| case EPROGMISMATCH: return "Program version wrong"; |
| case EPROCUNAVAIL: return "Bad procedure for program"; |
| case ENOLCK: return "No locks available"; |
| case ENOSYS: return "Function not implemented"; |
| case EFTYPE: return "Inappropriate file type or format"; |
| case EAUTH: return "Authentication error"; |
| case ENEEDAUTH: return "Need authenticator"; |
| case EIDRM: return "Identifier removed"; |
| case ENOMSG: return "No message of desired type"; |
| case EOVERFLOW: return "Value too large to be stored in data type"; |
| case ECANCELED: return "Operation canceled"; |
| case EILSEQ: return "Illegal byte sequence"; |
| case ENOATTR: return "Attribute not found"; |
| case EBADMSG: return "Bad message"; |
| case EMULTIHOP: return "Multihop attempted"; |
| case ENOLINK: return "Link has been severed"; |
| case EPROTO: return "Protocol error"; |
| case ENOTRECOVERABLE: return "State not recoverable"; |
| case EOWNERDEAD: return "Previous owner died"; |
| case ENODATA: return "No data available"; |
| case ETIME: return "Timer expired"; |
| case ENOTUNIQ: return "Name not unique on network"; |
| case ELIBBAD: return "Accessing a corrupted shared library"; |
| case EUCLEAN: return "Structure needs cleaning"; |
| case EREMOTEIO: return "Remote I/O error"; |
| case ENOMEDIUM: return "No medium found"; |
| case EMEDIUMTYPE: return "Wrong medium type"; |
| } |
| return NULL; |
| } |
| |
| #define MAKE_UNKNOWN_ERROR_MESSAGE(N,MSG) \ |
| do { \ |
| if((N) & 0x80000000) sprintf((MSG), "Unmapped NT status 0x%lx", (long int)((((N) << 4) & 0xf0000000) | ((N) & 0xffffff))); \ |
| else sprintf((MSG), "Unknown error %d", (N)); \ |
| } while(0) |
| |
| char *strerror(int e) { |
| const char *static_msg = get_static_error_message(e); |
| if(static_msg) return (char *)static_msg; |
| |
| static char msg[512]; |
| MAKE_UNKNOWN_ERROR_MESSAGE(e, msg); |
| errno = EINVAL; |
| return msg; |
| } |
| |
| char *_gnu_strerror_r(int number, char *buffer, size_t size) { |
| if(!size) { |
| errno = ERANGE; |
| return buffer; |
| } |
| char unknown_error_message[512]; |
| const char *message = get_static_error_message(number); |
| if(!message) { |
| MAKE_UNKNOWN_ERROR_MESSAGE(number, unknown_error_message); |
| message = unknown_error_message; |
| errno = EINVAL; |
| } |
| size_t len = strlen(message); |
| if(len > size - 1) { |
| len = size - 1; |
| errno = ERANGE; |
| } |
| buffer[len] = 0; |
| return memcpy(buffer, message, len); |
| } |
| |
| int _xpg_strerror_r(int number, char *buffer, size_t size) { |
| if(!size) return ERANGE; |
| //int orig_errno = errno; |
| int r = 0; |
| char unknown_error_message[512]; |
| const char *message = get_static_error_message(number); |
| if(!message) { |
| MAKE_UNKNOWN_ERROR_MESSAGE(number, unknown_error_message); |
| message = unknown_error_message; |
| r = EINVAL; |
| } |
| size_t len = strlen(message); |
| if(len > size - 1) { |
| len = size - 1; |
| r = ERANGE; |
| } |
| memcpy(buffer, message, len); |
| buffer[len] = 0; |
| //errno = orig_errno; |
| return r; |
| } |