1
0
mirror of https://github.com/TREX-CoE/qmckl.git synced 2024-12-22 20:36:01 +01:00
qmckl/org/qmckl_error.org

701 lines
22 KiB
Org Mode
Raw Normal View History

2021-03-09 01:16:23 +01:00
#+TITLE: Error handling
2021-04-30 01:26:19 +02:00
#+SETUPFILE: ../tools/theme.setup
#+INCLUDE: ../tools/lib.org
2021-03-09 01:16:23 +01:00
2021-03-10 12:58:38 +01:00
* Headers :noexport:
2021-03-09 01:16:23 +01:00
2021-03-30 14:51:23 +02:00
#+begin_src c :tangle (eval h_private_type)
#ifndef QMCKL_ERROR_HPT
#define QMCKL_ERROR_HPT
#+end_src
2021-03-09 01:16:23 +01:00
#+begin_src c :tangle (eval c)
2021-05-10 10:05:50 +02:00
#ifdef HAVE_CONFIG_H
2021-05-10 10:41:59 +02:00
#include "config.h"
2021-05-09 02:12:38 +02:00
#endif
2021-05-10 10:05:50 +02:00
#ifdef HAVE_STDINT_H
2021-03-09 01:16:23 +01:00
#include <stdint.h>
2021-05-10 10:05:50 +02:00
#elif HAVE_INTTYPES_H
#include <inttypes.h>
#endif
2021-03-30 14:51:23 +02:00
#include <string.h>
#include <assert.h>
#include <pthread.h>
#include <errno.h>
2021-05-11 13:57:23 +02:00
#include "qmckl.h"
2021-03-30 14:51:23 +02:00
#include "qmckl_context_private_type.h"
2021-03-09 01:16:23 +01:00
#+end_src
2021-03-05 03:45:30 +01:00
2021-03-09 01:16:23 +01:00
#+begin_src c :tangle (eval c_test) :noweb yes
#include <string.h>
#include <stdio.h>
2021-03-05 03:45:30 +01:00
#include "qmckl.h"
2021-05-11 16:41:03 +02:00
#include "assert.h"
#include "qmckl_error_private_type.h"
2021-05-10 10:05:50 +02:00
#ifdef HAVE_CONFIG_H
2021-05-10 10:41:59 +02:00
#include "config.h"
2021-05-09 02:12:38 +02:00
#endif
2021-05-11 16:41:03 +02:00
int main() {
2021-05-25 10:04:33 +02:00
qmckl_context context;
context = qmckl_context_create();
2021-03-09 01:16:23 +01:00
#+end_src
2021-03-05 03:45:30 +01:00
2021-03-18 18:02:06 +01:00
#+end_src
2021-03-19 19:02:43 +01:00
2022-02-24 19:06:19 +01:00
* -
2021-03-10 12:58:38 +01:00
:PROPERTIES:
:UNNUMBERED: t
:END:
2021-03-05 03:45:30 +01:00
2021-03-09 01:16:23 +01:00
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.
2021-04-30 01:26:19 +02:00
All the functions return with an exit code, defined as
2021-03-09 01:16:23 +01:00
#+NAME: type-exit-code
2021-03-30 14:51:23 +02:00
#+begin_src c :comments org :tangle (eval h_type)
2021-03-05 03:45:30 +01:00
typedef int32_t qmckl_exit_code;
2021-03-09 01:16:23 +01:00
#+end_src
2021-03-30 14:51:23 +02:00
#+begin_src f90 :comments org :tangle (eval fh_type) :exports none
integer , parameter :: qmckl_exit_code = c_int32_t
#+end_src
2021-03-09 01:16:23 +01:00
The exit code returns the completion status of the function to the
2021-03-10 12:58:38 +01:00
calling program. When a function call completed successfully,
~QMCKL_SUCCESS~ is returned. If one of the functions of
2021-03-09 01:16:23 +01:00
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
2021-03-19 18:17:01 +01:00
| 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_INVALID_ARG_11~ | 11 | 'Invalid argument 11' |
| ~QMCKL_INVALID_ARG_12~ | 12 | 'Invalid argument 12' |
| ~QMCKL_INVALID_ARG_13~ | 13 | 'Invalid argument 13' |
| ~QMCKL_INVALID_ARG_14~ | 14 | 'Invalid argument 14' |
| ~QMCKL_INVALID_ARG_15~ | 15 | 'Invalid argument 15' |
| ~QMCKL_INVALID_ARG_16~ | 16 | 'Invalid argument 16' |
| ~QMCKL_INVALID_ARG_17~ | 17 | 'Invalid argument 17' |
| ~QMCKL_INVALID_ARG_18~ | 18 | 'Invalid argument 18' |
| ~QMCKL_INVALID_ARG_19~ | 19 | 'Invalid argument 19' |
| ~QMCKL_INVALID_ARG_20~ | 20 | 'Invalid argument 20' |
2021-03-19 18:17:01 +01:00
| ~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' |
2021-05-15 23:19:13 +02:00
| ~QMCKL_NOT_PROVIDED~ | 106 | 'Not provided' |
2021-06-10 00:10:19 +02:00
| ~QMCKL_OUT_OF_BOUNDS~ | 107 | 'Index out of bounds' |
| ~QMCKL_ALREADY_SET~ | 108 | 'Already set' |
| ~QMCKL_INVALID_EXIT_CODE~ | 109 | 'Invalid exit code' |
2021-03-09 01:16:23 +01:00
# We need to force Emacs not to indent the Python code:
2021-04-30 01:26:19 +02:00
# -*- org-src-preserve-indentation: t
2021-03-10 12:58:38 +01:00
#+begin_src python :var table=table-exit-codes :results drawer :exports none
2021-03-05 03:45:30 +01:00
""" This script generates the C and Fortran constants for the error
codes from the org-mode table.
"""
2021-04-30 01:26:19 +02:00
result = [ "#+begin_src c :comments org :tangle (eval h_type) :exports none" ]
2021-03-19 18:17:01 +01:00
for (text, code,_) in table:
2021-03-05 03:45:30 +01:00
text=text.replace("~","")
2021-03-30 14:51:23 +02:00
result += [ f"#define {text:30s} ((qmckl_exit_code) {code:d})" ]
2021-03-09 01:16:23 +01:00
result += [ "#+end_src" ]
2021-04-30 01:26:19 +02:00
result += [ "" ]
2021-03-05 03:45:30 +01:00
2021-03-30 14:51:23 +02:00
result += [ "#+begin_src f90 :comments org :tangle (eval fh_type) :exports none" ]
2021-03-19 18:17:01 +01:00
for (text, code,_) in table:
2021-03-05 03:45:30 +01:00
text=text.replace("~","")
2021-03-30 14:51:23 +02:00
result += [ f" integer(qmckl_exit_code), parameter :: {text:30s} = {code:d}" ]
2021-03-09 01:16:23 +01:00
result += [ "#+end_src" ]
2021-03-05 03:45:30 +01:00
return '\n'.join(result)
2021-03-09 01:16:23 +01:00
#+end_src
#+RESULTS:
:results:
2021-03-30 14:51:23 +02:00
#+begin_src c :comments org :tangle (eval h_type) :exports none
#define QMCKL_SUCCESS ((qmckl_exit_code) 0)
#define QMCKL_INVALID_ARG_1 ((qmckl_exit_code) 1)
#define QMCKL_INVALID_ARG_2 ((qmckl_exit_code) 2)
#define QMCKL_INVALID_ARG_3 ((qmckl_exit_code) 3)
#define QMCKL_INVALID_ARG_4 ((qmckl_exit_code) 4)
#define QMCKL_INVALID_ARG_5 ((qmckl_exit_code) 5)
#define QMCKL_INVALID_ARG_6 ((qmckl_exit_code) 6)
#define QMCKL_INVALID_ARG_7 ((qmckl_exit_code) 7)
#define QMCKL_INVALID_ARG_8 ((qmckl_exit_code) 8)
#define QMCKL_INVALID_ARG_9 ((qmckl_exit_code) 9)
#define QMCKL_INVALID_ARG_10 ((qmckl_exit_code) 10)
#define QMCKL_INVALID_ARG_11 ((qmckl_exit_code) 11)
#define QMCKL_INVALID_ARG_12 ((qmckl_exit_code) 12)
#define QMCKL_INVALID_ARG_13 ((qmckl_exit_code) 13)
#define QMCKL_INVALID_ARG_14 ((qmckl_exit_code) 14)
#define QMCKL_INVALID_ARG_15 ((qmckl_exit_code) 15)
#define QMCKL_INVALID_ARG_16 ((qmckl_exit_code) 16)
#define QMCKL_INVALID_ARG_17 ((qmckl_exit_code) 17)
#define QMCKL_INVALID_ARG_18 ((qmckl_exit_code) 18)
#define QMCKL_INVALID_ARG_19 ((qmckl_exit_code) 19)
#define QMCKL_INVALID_ARG_20 ((qmckl_exit_code) 20)
2021-03-30 14:51:23 +02:00
#define QMCKL_FAILURE ((qmckl_exit_code) 101)
#define QMCKL_ERRNO ((qmckl_exit_code) 102)
#define QMCKL_INVALID_CONTEXT ((qmckl_exit_code) 103)
#define QMCKL_ALLOCATION_FAILED ((qmckl_exit_code) 104)
#define QMCKL_DEALLOCATION_FAILED ((qmckl_exit_code) 105)
2021-05-15 23:19:13 +02:00
#define QMCKL_NOT_PROVIDED ((qmckl_exit_code) 106)
2021-06-10 00:10:19 +02:00
#define QMCKL_OUT_OF_BOUNDS ((qmckl_exit_code) 107)
#define QMCKL_ALREADY_SET ((qmckl_exit_code) 108)
#define QMCKL_INVALID_EXIT_CODE ((qmckl_exit_code) 109)
2021-03-30 14:51:23 +02:00
#+end_src
#+begin_src f90 :comments org :tangle (eval fh_type) :exports none
integer(qmckl_exit_code), parameter :: QMCKL_SUCCESS = 0
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_1 = 1
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_2 = 2
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_3 = 3
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_4 = 4
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_5 = 5
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_6 = 6
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_7 = 7
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_8 = 8
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_9 = 9
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_10 = 10
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_11 = 11
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_12 = 12
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_13 = 13
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_14 = 14
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_15 = 15
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_16 = 16
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_17 = 17
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_18 = 18
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_19 = 19
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_ARG_20 = 20
2021-03-30 14:51:23 +02:00
integer(qmckl_exit_code), parameter :: QMCKL_FAILURE = 101
integer(qmckl_exit_code), parameter :: QMCKL_ERRNO = 102
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_CONTEXT = 103
integer(qmckl_exit_code), parameter :: QMCKL_ALLOCATION_FAILED = 104
integer(qmckl_exit_code), parameter :: QMCKL_DEALLOCATION_FAILED = 105
2021-05-15 23:19:13 +02:00
integer(qmckl_exit_code), parameter :: QMCKL_NOT_PROVIDED = 106
2021-06-10 00:10:19 +02:00
integer(qmckl_exit_code), parameter :: QMCKL_OUT_OF_BOUNDS = 107
integer(qmckl_exit_code), parameter :: QMCKL_ALREADY_SET = 108
integer(qmckl_exit_code), parameter :: QMCKL_INVALID_EXIT_CODE = 109
2021-03-09 01:16:23 +01:00
#+end_src
:end:
2021-03-05 03:45:30 +01:00
2021-03-30 22:40:56 +02:00
The ~qmckl_string_of_error~ converts an exit code into a string. The
2021-03-19 18:17:01 +01:00
string is assumed to be large enough to contain the error message
(typically 128 characters).
2022-02-24 19:06:19 +01:00
* hidden :noexport:
#+NAME: MAX_STRING_LENGTH
: 128
2021-03-30 22:40:56 +02:00
* Decoding errors
To decode the error messages, ~qmckl_string_of_error~ converts an
2021-04-30 01:26:19 +02:00
error code into a string.
2021-03-30 22:40:56 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval h_func) :noweb yes
const char*
qmckl_string_of_error (const qmckl_exit_code error);
#+end_src
2021-03-19 18:17:01 +01:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval h_private_func) :exports none :noweb yes
void
qmckl_string_of_error_f(const qmckl_exit_code error,
char result[<<MAX_STRING_LENGTH()>>]);
2021-03-19 18:17:01 +01:00
#+end_src
2021-04-30 01:26:19 +02:00
2021-03-19 18:17:01 +01:00
The text strings are extracted from the previous table.
#+NAME:cases
2021-03-29 01:17:33 +02:00
#+begin_src python :var table=table-exit-codes :exports none :noweb yes
2021-03-19 18:17:01 +01:00
""" This script extracts the text associated with the error codes
from the table.
"""
result = []
for (text, code, message) in table:
text = text.replace("~","")
2021-04-30 01:26:19 +02:00
message = message.replace("'",'"')
2021-03-19 18:17:01 +01:00
result += [ f"""case {text}:
2021-03-29 01:39:12 +02:00
return {message};
2022-04-05 11:03:38 +02:00
""" ]
2021-03-19 18:17:01 +01:00
return '\n'.join(result)
#+end_src
#+RESULTS: cases
#+begin_example
case QMCKL_SUCCESS:
2022-04-05 11:03:38 +02:00
return "Success";
case QMCKL_INVALID_ARG_1:
2022-04-05 11:03:38 +02:00
return "Invalid argument 1";
case QMCKL_INVALID_ARG_2:
2022-04-05 11:03:38 +02:00
return "Invalid argument 2";
case QMCKL_INVALID_ARG_3:
2022-04-05 11:03:38 +02:00
return "Invalid argument 3";
case QMCKL_INVALID_ARG_4:
2022-04-05 11:03:38 +02:00
return "Invalid argument 4";
case QMCKL_INVALID_ARG_5:
2022-04-05 11:03:38 +02:00
return "Invalid argument 5";
case QMCKL_INVALID_ARG_6:
2022-04-05 11:03:38 +02:00
return "Invalid argument 6";
case QMCKL_INVALID_ARG_7:
2022-04-05 11:03:38 +02:00
return "Invalid argument 7";
case QMCKL_INVALID_ARG_8:
2022-04-05 11:03:38 +02:00
return "Invalid argument 8";
case QMCKL_INVALID_ARG_9:
2022-04-05 11:03:38 +02:00
return "Invalid argument 9";
case QMCKL_INVALID_ARG_10:
2022-04-05 11:03:38 +02:00
return "Invalid argument 10";
case QMCKL_INVALID_ARG_11:
2022-04-05 11:03:38 +02:00
return "Invalid argument 11";
case QMCKL_INVALID_ARG_12:
2022-04-05 11:03:38 +02:00
return "Invalid argument 12";
case QMCKL_INVALID_ARG_13:
2022-04-05 11:03:38 +02:00
return "Invalid argument 13";
case QMCKL_INVALID_ARG_14:
2022-04-05 11:03:38 +02:00
return "Invalid argument 14";
case QMCKL_INVALID_ARG_15:
2022-04-05 11:03:38 +02:00
return "Invalid argument 15";
case QMCKL_INVALID_ARG_16:
2022-04-05 11:03:38 +02:00
return "Invalid argument 16";
case QMCKL_INVALID_ARG_17:
2022-04-05 11:03:38 +02:00
return "Invalid argument 17";
case QMCKL_INVALID_ARG_18:
2022-04-05 11:03:38 +02:00
return "Invalid argument 18";
case QMCKL_INVALID_ARG_19:
2022-04-05 11:03:38 +02:00
return "Invalid argument 19";
case QMCKL_INVALID_ARG_20:
2022-04-05 11:03:38 +02:00
return "Invalid argument 20";
case QMCKL_FAILURE:
2022-04-05 11:03:38 +02:00
return "Failure";
case QMCKL_ERRNO:
2022-04-05 11:03:38 +02:00
return strerror(errno);
case QMCKL_INVALID_CONTEXT:
2022-04-05 11:03:38 +02:00
return "Invalid context";
case QMCKL_ALLOCATION_FAILED:
2022-04-05 11:03:38 +02:00
return "Allocation failed";
case QMCKL_DEALLOCATION_FAILED:
2022-04-05 11:03:38 +02:00
return "De-allocation failed";
case QMCKL_NOT_PROVIDED:
2022-04-05 11:03:38 +02:00
return "Not provided";
case QMCKL_OUT_OF_BOUNDS:
return "Index out of bounds";
case QMCKL_ALREADY_SET:
return "Already set";
case QMCKL_INVALID_EXIT_CODE:
2022-04-05 11:03:38 +02:00
return "Invalid exit code";
#+end_example
2021-04-30 01:26:19 +02:00
# Source
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :noweb yes :exports none
2021-03-29 01:39:12 +02:00
const char* qmckl_string_of_error(const qmckl_exit_code error) {
2021-03-19 18:17:01 +01:00
switch (error) {
<<cases()>>
}
2021-03-29 01:39:12 +02:00
return "Unknown error";
}
void qmckl_string_of_error_f(const qmckl_exit_code error, char result[<<MAX_STRING_LENGTH()>>]) {
2021-05-07 12:47:56 +02:00
strncpy(result, qmckl_string_of_error(error), <<MAX_STRING_LENGTH()>>-1);
2021-03-19 18:17:01 +01:00
}
#+end_src
2021-04-30 01:26:19 +02:00
# Fortran interface
2022-02-24 19:06:19 +01:00
#+begin_src f90 :tangle (eval fh_func) :exports none :noweb yes
interface
2021-03-29 01:39:12 +02:00
subroutine qmckl_string_of_error (error, string) bind(C, name='qmckl_string_of_error_f')
use, intrinsic :: iso_c_binding
2021-03-30 14:51:23 +02:00
import
2022-08-10 14:30:04 +02:00
implicit none
2021-03-30 14:51:23 +02:00
integer (qmckl_exit_code), intent(in), value :: error
2021-03-19 19:11:06 +01:00
character, intent(out) :: string(<<MAX_STRING_LENGTH()>>)
end subroutine qmckl_string_of_error
end interface
#+end_src
2021-03-30 14:51:23 +02:00
* Data structure in context
2022-02-24 19:06:19 +01:00
The strings are declared internally with a maximum fixed size to avoid
2021-03-30 14:51:23 +02:00
dynamic memory allocation.
#+begin_src c :comments org :tangle (eval h_private_type)
#define QMCKL_MAX_FUN_LEN 256
#define QMCKL_MAX_MSG_LEN 1024
typedef struct qmckl_error_struct {
qmckl_exit_code exit_code;
char function[QMCKL_MAX_FUN_LEN];
char message [QMCKL_MAX_MSG_LEN];
} qmckl_error_struct;
#+end_src
* Updating errors in the context
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
The error is updated in the context using ~qmckl_set_error~.
2021-03-30 14:51:23 +02:00
When the error is set in the context, it is mandatory to specify
from which function the error is triggered, and a message
explaining the error. The exit code can't be ~QMCKL_SUCCESS~.
# Header
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval h_func)
2021-03-30 14:51:23 +02:00
qmckl_exit_code
qmckl_set_error(qmckl_context context,
const qmckl_exit_code exit_code,
const char* function_name,
const char* message);
#+end_src
# Source
2022-02-24 19:06:19 +01:00
#+begin_src c :tangle (eval c) :exports none
2021-03-30 14:51:23 +02:00
qmckl_exit_code
qmckl_set_error(qmckl_context context,
const qmckl_exit_code exit_code,
const char* function_name,
const char* message)
{
/* Passing a function name and a message is mandatory. */
assert (function_name != NULL);
assert (message != NULL);
/* Exit codes are assumed valid. */
assert (exit_code >= 0);
assert (exit_code != QMCKL_SUCCESS);
assert (exit_code < QMCKL_INVALID_EXIT_CODE);
/* The context is assumed to exist. */
assert (qmckl_context_check(context) != QMCKL_NULL_CONTEXT);
qmckl_lock(context);
{
2022-04-05 11:03:38 +02:00
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
2021-03-30 14:51:23 +02:00
assert (ctx != NULL); /* Impossible because the context is valid. */
2021-04-30 01:26:19 +02:00
2021-03-30 14:51:23 +02:00
ctx->error.exit_code = exit_code;
2021-05-07 12:47:56 +02:00
strncpy(ctx->error.function, function_name, QMCKL_MAX_FUN_LEN-1);
strncpy(ctx->error.message, message, QMCKL_MAX_MSG_LEN-1);
2021-03-30 14:51:23 +02:00
}
qmckl_unlock(context);
2021-04-30 01:26:19 +02:00
2021-03-30 14:51:23 +02:00
return QMCKL_SUCCESS;
}
#+end_src
2021-05-25 09:59:37 +02:00
* Get the error
Upon error, the error type and message can be obtained from the
context using ~qmckl_get_error~. The message and function name
is returned in the variables provided. Therefore, passing a
function name and message is mandatory.
# Header
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval h_func)
2021-05-25 09:59:37 +02:00
qmckl_exit_code
qmckl_get_error(qmckl_context context,
qmckl_exit_code *exit_code,
char* function_name,
char* message);
2021-05-25 09:59:37 +02:00
#+end_src
2021-03-30 14:51:23 +02:00
2021-05-25 09:59:37 +02:00
# Source
2022-02-24 19:06:19 +01:00
#+begin_src c :tangle (eval c) :exports none
2021-05-25 09:59:37 +02:00
qmckl_exit_code
qmckl_get_error(qmckl_context context,
qmckl_exit_code *exit_code,
char* function_name,
char* message)
2021-05-25 09:59:37 +02:00
{
/* Passing a function name and a message is mandatory. */
assert (function_name != NULL);
assert (message != NULL);
/* The context is assumed to exist. */
assert (qmckl_context_check(context) != QMCKL_NULL_CONTEXT);
qmckl_lock(context);
{
2022-04-05 11:03:38 +02:00
qmckl_context_struct* const ctx = (qmckl_context_struct*) context;
2021-05-25 09:59:37 +02:00
assert (ctx != NULL); /* Impossible because the context is valid. */
2021-10-14 18:53:31 +02:00
/* Turn off annoying GCC warning */
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"
#endif
2021-05-25 09:59:37 +02:00
strncpy(function_name, ctx->error.function, QMCKL_MAX_FUN_LEN-1);
strncpy(message , ctx->error.message , QMCKL_MAX_MSG_LEN-1);
2021-10-14 18:53:31 +02:00
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
(*exit_code) = ctx->error.exit_code;
2021-05-25 09:59:37 +02:00
}
qmckl_unlock(context);
return QMCKL_SUCCESS;
}
#+end_src
* Failing
2021-03-30 14:51:23 +02:00
To make a function fail, the ~qmckl_failwith~ function should be
called, such that information about the failure is stored in
the context. The desired exit code is given as an argument, as
2021-03-30 22:40:56 +02:00
well as the name of the function and an error message. If the
message is ~NULL~, then the default message obtained by
~qmckl_string_of_error~ is used. The return code of the function is
the desired return code.
Upon failure, a ~QMCKL_NULL_CONTEXT~ is returned.
2021-03-30 14:51:23 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval h_func)
qmckl_exit_code
qmckl_failwith(qmckl_context context,
const qmckl_exit_code exit_code,
const char* function,
const char* message) ;
2021-03-30 14:51:23 +02:00
#+end_src
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_exit_code
qmckl_failwith(qmckl_context context,
const qmckl_exit_code exit_code,
const char* function,
const char* message)
{
2021-03-30 14:51:23 +02:00
assert (exit_code > 0);
assert (exit_code < QMCKL_INVALID_EXIT_CODE);
assert (function != NULL);
assert (strlen(function) < QMCKL_MAX_FUN_LEN);
2021-03-30 22:40:56 +02:00
if (message != NULL) {
assert (strlen(message) < QMCKL_MAX_MSG_LEN);
}
2021-03-30 14:51:23 +02:00
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT)
2021-03-30 22:40:56 +02:00
return QMCKL_INVALID_CONTEXT;
2021-04-30 01:26:19 +02:00
2021-03-30 22:40:56 +02:00
if (message == NULL) {
2021-04-30 01:26:19 +02:00
qmckl_exit_code rc =
2021-03-30 22:40:56 +02:00
qmckl_set_error(context, exit_code, function, qmckl_string_of_error(exit_code));
assert (rc == QMCKL_SUCCESS);
} else {
2021-04-30 01:26:19 +02:00
qmckl_exit_code rc =
2021-03-30 22:40:56 +02:00
qmckl_set_error(context, exit_code, function, message);
assert (rc == QMCKL_SUCCESS);
}
2021-03-30 14:51:23 +02:00
return exit_code;
}
#+end_src
For example, this function can be used as
#+begin_src c :tangle no
if (x < 0) {
return qmckl_failwith(context,
QMCKL_INVALID_ARG_2,
2021-04-30 01:26:19 +02:00
"qmckl_function",
2021-03-30 14:51:23 +02:00
"Expected x >= 0");
}
#+end_src
2021-04-30 01:26:19 +02:00
2022-07-11 15:19:09 +02:00
* Last error
2021-03-30 14:51:23 +02:00
2022-07-11 15:19:09 +02:00
Returns a string describing the last error, using ~qmckl_get_error~.
# Header
#+begin_src c :comments org :tangle (eval h_func)
qmckl_exit_code
qmckl_last_error(qmckl_context context, char* buffer);
#+end_src
# Source
#+begin_src c :tangle (eval c) :exports none
qmckl_exit_code
qmckl_last_error(qmckl_context context, char* buffer) {
char function_name[QMCKL_MAX_FUN_LEN];
char message[QMCKL_MAX_MSG_LEN];
qmckl_exit_code rc, last_rc;
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
strncpy(buffer, "Null context", 13);
return QMCKL_FAILURE;
}
rc = qmckl_get_error(context, &last_rc, function_name, message);
if (rc != QMCKL_SUCCESS) {
return rc;
}
sprintf(buffer, "Error -- %s -- in %s\n%s",
qmckl_string_of_error(last_rc),
function_name, message);
return QMCKL_SUCCESS;
}
#+end_src
2022-08-10 14:30:04 +02:00
** Fortran inteface
#+begin_src f90 :tangle (eval fh_func) :exports none :noweb yes
interface
subroutine qmckl_last_error (context, string) bind(C, name='qmckl_last_error')
use, intrinsic :: iso_c_binding
import
implicit none
integer (c_int64_t) , intent(in), value :: context
character, intent(out) :: string(*)
end subroutine qmckl_last_error
end interface
#+end_src
* Helper functions for debugging
The following function prints to ~stderr~ an error message is the return code is
not ~QMCKL_SUCCESS~.
# Header
#+begin_src c :comments org :tangle (eval h_func)
qmckl_exit_code
qmckl_check(qmckl_context context, qmckl_exit_code rc);
#+end_src
# Source
#+begin_src c :tangle (eval c) :exports none
#include <stdio.h>
qmckl_exit_code
qmckl_check(qmckl_context context, qmckl_exit_code rc)
{
if (rc != QMCKL_SUCCESS) {
2023-01-26 17:46:39 +01:00
char fname[QMCKL_MAX_FUN_LEN];
char message[QMCKL_MAX_MSG_LEN];
fprintf(stderr, "===========\nQMCKL ERROR\n%s\n", qmckl_string_of_error(rc));
qmckl_get_error(context, &rc, fname, message);
fprintf(stderr, "Function: %s\nMessage: %s\n===========\n", fname, message);
}
return rc;
}
#+end_src
It should be used as:
#+begin_src c
rc = qmckl_check(context,
qmckl_...(context, ...)
);
assert (rc == QMCKL_SUCCESS);
#+end_src
** Fortran inteface
#+begin_src f90 :tangle (eval fh_func) :exports none :noweb yes
interface
function qmckl_check (context, rc) bind(C, name='qmckl_check')
use, intrinsic :: iso_c_binding
import
implicit none
integer(qmckl_exit_code) :: qmckl_check
integer (c_int64_t) , intent(in), value :: context
2022-11-16 17:54:59 +01:00
integer(qmckl_exit_code), intent(in), value :: rc
end function qmckl_check
end interface
#+end_src
2021-03-10 12:58:38 +01:00
* End of files :noexport:
2021-03-05 03:45:30 +01:00
2021-03-30 14:51:23 +02:00
#+begin_src c :comments link :tangle (eval h_private_type)
#endif
#+end_src
#+begin_src c :comments link :tangle (eval c_test)
/* Initialize the variables */
char function_name[QMCKL_MAX_FUN_LEN]="";
char message[QMCKL_MAX_MSG_LEN]="";
/* Set the error code to be different from Success */
2021-05-25 10:04:33 +02:00
qmckl_exit_code exit_code;
exit_code = 1;
assert (qmckl_set_error(context, exit_code, "my_function", "Message") == QMCKL_SUCCESS);
assert (qmckl_get_error(context, &exit_code, function_name, message) == QMCKL_SUCCESS);
assert (exit_code == 1);
assert (strcmp(function_name,"my_function") == 0);
assert (strcmp(message,"Message") == 0);
2022-07-08 17:43:11 +02:00
exit_code = qmckl_context_destroy(context);
assert(exit_code == QMCKL_SUCCESS);
2021-05-25 10:04:33 +02:00
return 0;
2021-03-05 03:45:30 +01:00
}
2021-03-30 14:51:23 +02:00
#+end_src
2021-03-05 03:45:30 +01:00
2022-08-10 14:30:04 +02:00
# -*- mode: org -*-
# vim: syntax=c
2021-03-05 03:45:30 +01:00