mirror of
https://github.com/TREX-CoE/qmckl.git
synced 2024-11-19 12:32:40 +01:00
194 lines
6.6 KiB
Org Mode
194 lines
6.6 KiB
Org Mode
|
# This file is part of the qmckl.h file
|
||
|
** Error handling
|
||
|
:PROPERTIES:
|
||
|
:c: qmckl_error.c
|
||
|
:c_test: test_qmckl_error.c
|
||
|
:fh: qmckl_f.f90
|
||
|
:h: qmckl.h
|
||
|
:END:
|
||
|
|
||
|
This file is written in C because it is more natural to express the
|
||
|
error handling in C than in Fortran.
|
||
|
|
||
|
2 files are produced:
|
||
|
- a source file : =qmckl_error.c=
|
||
|
- a test file : =test_qmckl_error.c=
|
||
|
|
||
|
*** Headers :noexport:
|
||
|
#+BEGIN_SRC C :tangle (org-entry-get nil "c" t)
|
||
|
#include "qmckl.h"
|
||
|
#include <math.h>
|
||
|
#include <string.h>
|
||
|
#include <errno.h>
|
||
|
#include <assert.h>
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC C :tangle (org-entry-get nil "c_test" t)
|
||
|
#include "qmckl.h"
|
||
|
#include "munit.h"
|
||
|
MunitResult test_qmckl_error() {
|
||
|
#+END_SRC
|
||
|
|
||
|
*** Error handling
|
||
|
|
||
|
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 qmckl.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, the
|
||
|
~QMCKL_SUCCESS~ exit code 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
|
||
|
| ~QMCKL_SUCCESS~ | 0 |
|
||
|
| ~QMCKL_INVALID_ARG_1~ | 1 |
|
||
|
| ~QMCKL_INVALID_ARG_2~ | 2 |
|
||
|
| ~QMCKL_INVALID_ARG_3~ | 3 |
|
||
|
| ~QMCKL_INVALID_ARG_4~ | 4 |
|
||
|
| ~QMCKL_INVALID_ARG_5~ | 5 |
|
||
|
| ~QMCKL_INVALID_ARG_6~ | 6 |
|
||
|
| ~QMCKL_INVALID_ARG_7~ | 7 |
|
||
|
| ~QMCKL_INVALID_ARG_8~ | 8 |
|
||
|
| ~QMCKL_INVALID_ARG_9~ | 9 |
|
||
|
| ~QMCKL_INVALID_ARG_10~ | 10 |
|
||
|
| ~QMCKL_NULL_CONTEXT~ | 101 |
|
||
|
| ~QMCKL_FAILURE~ | 102 |
|
||
|
| ~QMCKL_ERRNO~ | 103 |
|
||
|
| ~QMCKL_INVALID_EXIT_CODE~ | 104 |
|
||
|
|
||
|
# 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 result
|
||
|
""" This script generates the C and Fortran constants for the error
|
||
|
codes from the org-mode table.
|
||
|
"""
|
||
|
|
||
|
result = [ "#+BEGIN_SRC C :comments org :tangle qmckl.h" ]
|
||
|
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 qmckl_f.f90" ]
|
||
|
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 qmckl.h
|
||
|
#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_NULL_CONTEXT 101
|
||
|
#define QMCKL_FAILURE 102
|
||
|
#define QMCKL_ERRNO 103
|
||
|
#define QMCKL_INVALID_EXIT_CODE 104
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC f90 :comments org :tangle qmckl_f.f90
|
||
|
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_NULL_CONTEXT = 101
|
||
|
integer, parameter :: QMCKL_FAILURE = 102
|
||
|
integer, parameter :: QMCKL_ERRNO = 103
|
||
|
integer, parameter :: QMCKL_INVALID_EXIT_CODE = 104
|
||
|
#+END_SRC
|
||
|
:end:
|
||
|
|
||
|
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
|
||
|
well as the name of the function and an error message. The return
|
||
|
code of the function is the desired return code.
|
||
|
|
||
|
#+BEGIN_SRC C :comments org :tangle qmckl.h
|
||
|
qmckl_exit_code qmckl_failwith(qmckl_context context,
|
||
|
const qmckl_exit_code exit_code,
|
||
|
const char* function,
|
||
|
const char* message) ;
|
||
|
#+END_SRC
|
||
|
|
||
|
#+BEGIN_SRC C :comments org :tangle qmckl_error.c
|
||
|
qmckl_exit_code qmckl_failwith(qmckl_context context,
|
||
|
const qmckl_exit_code exit_code,
|
||
|
const char* function,
|
||
|
const char* message) {
|
||
|
if (context == 0) return QMCKL_NULL_CONTEXT;
|
||
|
assert (exit_code > 0);
|
||
|
assert (exit_code < QMCKL_INVALID_EXIT_CODE);
|
||
|
assert (function != NULL);
|
||
|
assert (message != NULL);
|
||
|
assert (strlen(function) < QMCKL_MAX_FUN_LEN);
|
||
|
assert (strlen(message) < QMCKL_MAX_MSG_LEN);
|
||
|
|
||
|
context = qmckl_context_set_error(context, exit_code, function, message);
|
||
|
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,
|
||
|
"qmckl_function",
|
||
|
"Expected x >= 0");
|
||
|
}
|
||
|
#+END_SRC
|
||
|
|
||
|
|
||
|
# To decode the error messages, the <<<~qmckl_strerror~>>> converts an
|
||
|
# error code into a string.
|
||
|
|
||
|
*** End of files :noexport:
|
||
|
|
||
|
***** Test
|
||
|
#+BEGIN_SRC C :comments link :tangle (org-entry-get nil "c_test" t)
|
||
|
return MUNIT_OK;
|
||
|
}
|
||
|
#+END_SRC
|
||
|
|
||
|
|
||
|
|
||
|
# -*- mode: org -*-
|
||
|
# vim: syntax=c
|
||
|
|
||
|
# -*- mode: org -*-
|
||
|
# vim: syntax=c
|