/** * ========================================================================= * File : lib_errors.cpp * Project : 0 A.D. * Description : error handling system: defines error codes, associates * : them with descriptive text, simplifies error notification. * * @author Jan.Wassenberg@stud.uni-karlsruhe.de * ========================================================================= */ /* * Copyright (c) 2005 Jan Wassenberg * * Redistribution and/or modification are also permitted under the * terms of the GNU General Public License as published by the * Free Software Foundation (version 2 or later, at your option). * * 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. */ // note: this is called lib_errors.cpp because we have another // errors.cpp; the MS linker isn't smart enough to deal with // object files of the same name but in different paths. #include "precompiled.h" #include "lib_errors.h" #include "lib/sysdep/sysdep.h" #include #include // abs #include static const char* LibError_description(LibError err) { // not in our range const int ierr = abs((int)err); if(!(ERR_MIN <= ierr && ierr < ERR_MAX)) return 0; switch(err) { #define ERR(err, id, str) case id: return str; #include "lib_errors.h" default: return "Unknown error"; } UNREACHABLE; } // generate textual description of an error code. // stores up to in the given buffer. // if error is unknown/invalid, the string will be something like // "Unknown error (65536, 0x10000)". char* error_description_r(LibError err, char* buf, size_t max_chars) { // lib error const char* str = LibError_description(err); if(str) { // was one of our error codes (chosen so as not to conflict // with any others), so we're done. strcpy_s(buf, max_chars, str); } // unknown else { snprintf(buf, max_chars, "Unknown error (%d, 0x%X)", err, err); } return buf; } // return the LibError equivalent of errno, or ERR_FAIL if there's no equal. // only call after a POSIX function indicates failure. // raises a warning (avoids having to on each call site). LibError LibError_from_errno(bool warn_if_failed) { LibError err; switch(errno) { case ENOMEM: err = ERR_NO_MEM; break; case EINVAL: err = ERR_INVALID_PARAM; break; case ENOSYS: err = ERR_NOT_IMPLEMENTED; break; case ENOENT: err = ERR_TNODE_NOT_FOUND; break; case EACCES: err = ERR_FILE_ACCESS; break; case EIO: err = ERR_IO; break; case ENAMETOOLONG: err = ERR_PATH_LENGTH; break; default: err = ERR_FAIL; break; } if(warn_if_failed) DEBUG_WARN_ERR(err); return err; } // translate the return value of any POSIX function into LibError. // ret is typically to -1 to indicate error and 0 on success. // you should set errno to 0 before calling the POSIX function to // make sure we do not return any stale errors. LibError LibError_from_posix(int ret, bool warn_if_failed) { debug_assert(ret == 0 || ret == -1); if(ret == 0) return INFO_OK; return LibError_from_errno(warn_if_failed); } // return the errno.h equivalent of . // does not assign to errno (this simplifies code by allowing direct return) static int return_errno_from_LibError(LibError err) { switch(err) { case ERR_NO_MEM: return ENOMEM; case ERR_INVALID_PARAM: return EINVAL; case ERR_NOT_IMPLEMENTED: return ENOSYS; case ERR_TNODE_NOT_FOUND: return ENOENT; case ERR_FILE_ACCESS: return EACCES; case ERR_IO: return EIO; case ERR_PATH_LENGTH: return ENAMETOOLONG; // somewhat of a quandary: the set of errnos in wposix.h doesn't // have an "unknown error". we pick EPERM because we don't expect // that to come up often otherwise. default: return EPERM; } } // set errno to the equivalent of . used in wposix - underlying // functions return LibError but must be translated to errno at // e.g. the mmap interface level. higher-level code that calls mmap will // in turn convert back to LibError. void LibError_set_errno(LibError err) { errno = return_errno_from_LibError(err); }