#+TITLE: Error handling #+SETUPFILE: ../docs/theme.setup * Headers :noexport: #+NAME: filename #+begin_src elisp tangle: no (file-name-nondirectory (substring buffer-file-name 0 -4)) #+end_src #+begin_src c :tangle (eval c) #include #include "qmckl_error.h" #+end_src #+begin_src c :tangle (eval c_test) :noweb yes #include "qmckl.h" #include "munit.h" MunitResult test_<>() { #+end_src #+begin_src c :comments org :tangle (eval h) #include #include #+end_src * :PROPERTIES: :UNNUMBERED: t :END: The library should never make the calling programs abort, nor perform any input/output operations. This decision has to be taken by the developer of the code calling the library. All the functions return with an exit code, defined as #+NAME: type-exit-code #+begin_src c :comments org :tangle (eval h) typedef int32_t qmckl_exit_code; #+end_src The exit code returns the completion status of the function to the calling program. When a function call completed successfully, ~QMCKL_SUCCESS~ is returned. If one of the functions of the library fails to complete the requested task, an appropriate error code is returned to the program. Here is the complete list of exit codes. #+NAME: table-exit-codes | Macro | Code | Description | |-----------------------------+------+------------------------| | ~QMCKL_SUCCESS~ | 0 | 'Success' | | ~QMCKL_INVALID_ARG_1~ | 1 | 'Invalid argument 1' | | ~QMCKL_INVALID_ARG_2~ | 2 | 'Invalid argument 2' | | ~QMCKL_INVALID_ARG_3~ | 3 | 'Invalid argument 3' | | ~QMCKL_INVALID_ARG_4~ | 4 | 'Invalid argument 4' | | ~QMCKL_INVALID_ARG_5~ | 5 | 'Invalid argument 5' | | ~QMCKL_INVALID_ARG_6~ | 6 | 'Invalid argument 6' | | ~QMCKL_INVALID_ARG_7~ | 7 | 'Invalid argument 7' | | ~QMCKL_INVALID_ARG_8~ | 8 | 'Invalid argument 8' | | ~QMCKL_INVALID_ARG_9~ | 9 | 'Invalid argument 9' | | ~QMCKL_INVALID_ARG_10~ | 10 | 'Invalid argument 10' | | ~QMCKL_FAILURE~ | 101 | 'Failure' | | ~QMCKL_ERRNO~ | 102 | strerror(errno) | | ~QMCKL_INVALID_CONTEXT~ | 103 | 'Invalid context' | | ~QMCKL_ALLOCATION_FAILED~ | 104 | 'Allocation failed' | | ~QMCKL_DEALLOCATION_FAILED~ | 105 | 'De-allocation failed' | | ~QMCKL_INVALID_EXIT_CODE~ | 106 | 'Invalid exit code' | # We need to force Emacs not to indent the Python code: # -*- org-src-preserve-indentation: t #+begin_src python :var table=table-exit-codes :results drawer :exports none """ This script generates the C and Fortran constants for the error codes from the org-mode table. """ result = [ "#+begin_src c :comments org :tangle (eval h) :exports none" ] for (text, code,_) in table: text=text.replace("~","") result += [ f"#define {text:30s} {code:d}" ] result += [ "#+end_src" ] result += [ "" ] result += [ "#+begin_src f90 :comments org :tangle (eval fh) :exports none" ] for (text, code,_) in table: text=text.replace("~","") result += [ f" integer, parameter :: {text:30s} = {code:d}" ] result += [ "#+end_src" ] return '\n'.join(result) #+end_src #+RESULTS: :results: #+begin_src c :comments org :tangle (eval h) :exports none #define QMCKL_SUCCESS 0 #define QMCKL_INVALID_ARG_1 1 #define QMCKL_INVALID_ARG_2 2 #define QMCKL_INVALID_ARG_3 3 #define QMCKL_INVALID_ARG_4 4 #define QMCKL_INVALID_ARG_5 5 #define QMCKL_INVALID_ARG_6 6 #define QMCKL_INVALID_ARG_7 7 #define QMCKL_INVALID_ARG_8 8 #define QMCKL_INVALID_ARG_9 9 #define QMCKL_INVALID_ARG_10 10 #define QMCKL_FAILURE 101 #define QMCKL_ERRNO 102 #define QMCKL_INVALID_CONTEXT 103 #define QMCKL_ALLOCATION_FAILED 104 #define QMCKL_DEALLOCATION_FAILED 105 #define QMCKL_INVALID_EXIT_CODE 106 #+end_src #+begin_src f90 :comments org :tangle (eval fh) :exports none integer, parameter :: QMCKL_SUCCESS = 0 integer, parameter :: QMCKL_INVALID_ARG_1 = 1 integer, parameter :: QMCKL_INVALID_ARG_2 = 2 integer, parameter :: QMCKL_INVALID_ARG_3 = 3 integer, parameter :: QMCKL_INVALID_ARG_4 = 4 integer, parameter :: QMCKL_INVALID_ARG_5 = 5 integer, parameter :: QMCKL_INVALID_ARG_6 = 6 integer, parameter :: QMCKL_INVALID_ARG_7 = 7 integer, parameter :: QMCKL_INVALID_ARG_8 = 8 integer, parameter :: QMCKL_INVALID_ARG_9 = 9 integer, parameter :: QMCKL_INVALID_ARG_10 = 10 integer, parameter :: QMCKL_FAILURE = 101 integer, parameter :: QMCKL_ERRNO = 102 integer, parameter :: QMCKL_INVALID_CONTEXT = 103 integer, parameter :: QMCKL_ALLOCATION_FAILED = 104 integer, parameter :: QMCKL_DEALLOCATION_FAILED = 105 integer, parameter :: QMCKL_INVALID_EXIT_CODE = 106 #+end_src :end: The ~qmckl_strerror~ converts an exit code into a string. The string is assumed to be large enough to contain the error message (typically 128 characters). #+NAME: MAX_STRING_LENGTH : 128 #+begin_src c :comments org :tangle (eval h) :exports none :noweb yes void qmckl_string_of_error(qmckl_exit_code error, char string[<>]); #+end_src The text strings are extracted from the previous table. #+NAME:cases #+begin_src python :var table=table-exit-codes :exports none """ This script extracts the text associated with the error codes from the table. """ result = [] for (text, code, message) in table: text = text.replace("~","") message = message.replace("'",'"') result += [ f"""case {text}: message = {message}; break;""" ] return '\n'.join(result) #+end_src # Source #+begin_src c :comments org :tangle (eval c) :noweb yes void qmckl_string_of_error(qmckl_exit_code error, char string[<>]) { char* message; switch (error) { <> } strncpy(string,message,<>); } #+end_src # Fortran interface #+begin_src f90 :tangle (eval fh) :noexport :noweb yes interface type (c_ptr) function qmckl_string_of_error (error, string) bind(C) use, intrinsic :: iso_c_binding integer (c_int32_t), intent(in), value :: error character*(<>), intent(out) :: string end function qmckl_string_of_error end interface #+end_src * End of files :noexport: ** Test #+begin_src c :comments link :tangle (eval c_test) return MUNIT_OK; } #+end_src # -*- mode: org -*- # vim: syntax=c