/ include / leutils / status.h
status.h
  1  /*
  2   * SPDX-FileCopyrightText: 2023-2024 Le’
  3   *
  4   * SPDX-License-Identifier: LGPL-3.0-or-later
  5   */
  6  
  7  #ifndef LE_STATUS_H
  8  # define LE_STATUS_H
  9  
 10  # include <stdint.h>
 11  # include <stddef.h>
 12  
 13  # ifdef __cplusplus
 14  extern "C" {
 15  # endif
 16  
 17    /*
 18     * The status code structure is modelled after OpenVMS condition codes.
 19     * As a matter of fact, they are exactly the same, with one exceptions:
 20     *
 21     *   The UNIT and REASON fields must always have their highest bit set,
 22     *   thus making them user generated codes, not to be mixed with system
 23     *   codes.
 24     */
 25  
 26    typedef uint32_t LE_STATUS;
 27  
 28  # define LE_M_STATUS_CONTROL            UINT32_C(0xF0000000)
 29  # define LE_V_STATUS_CONTROL            28
 30  # define LE_M_STATUS_UNIT               UINT32_C(0x0FFF0000)
 31  # define LE_V_STATUS_UNIT               16
 32  # define LE_M_STATUS_REASON             UINT32_C(0x0000FFF8)
 33  # define LE_V_STATUS_REASON             3
 34  # define LE_M_STATUS_SEVERITY           UINT32_C(0x00000007)
 35  # define LE_V_STATUS_SEVERITY           0
 36  
 37  # define LE_status_control(sts)                                         \
 38    (((sts) & LE_M_STATUS_CONTROL) >> LE_V_STATUS_CONTROL)
 39  # define LE_status_module(sts)                                          \
 40    (((sts) & LE_M_STATUS_MODULE) >> LE_V_STATUS_MODULE)
 41  # define LE_status_code(sts)                                            \
 42    (((sts) & LE_M_STATUS_CODE) >> LE_V_STATUS_CODE)
 43  # define LE_status_severity(sts)                                        \
 44    (((sts) & LE_M_STATUS_SEVERITY) >> LE_V_STATUS_SEVERITY)
 45  
 46  # define LE_STATUS_SEVERITY_WARNING     0
 47  # define LE_STATUS_SEVERITY_SUCCESS     1
 48  # define LE_STATUS_SEVERITY_ERROR       2
 49  # define LE_STATUS_SEVERITY_INFORMATION 3
 50  # define LE_STATUS_SEVERITY_SEVERE      4
 51  # define LE_STATUS_SEVERITY_FATAL       4
 52  # define LE_status_is_OK(status)                                        \
 53    (((status) & 1) != 0)
 54  # define LE_status_is_warning(status)                                   \
 55    (LE_status_severity(status) == LE_STATUS_SEVERITY_WARNING)
 56  # define LE_status_is_success(status)                                   \
 57    (LE_status_severity(status) == LE_STATUS_SEVERITY_SUCCESS)
 58  # define LE_status_is_error(status)                                     \
 59    (LE_status_severity(status) == LE_STATUS_SEVERITY_ERROR)
 60  # define LE_status_is_information(status)                               \
 61    (LE_status_severity(status) == LE_STATUS_SEVERITY_INFORMATION)
 62  # define LE_status_is_severe(status)                                    \
 63    (LE_status_severity(status) == LE_STATUS_SEVERITY_SEVERE)
 64  # define LE_status_is_fatal(status)                                     \
 65    (LE_status_severity(status) == LE_STATUS_SEVERITY_FATAL)
 66  
 67    /*
 68     * Unit 0 isn't a unit at all, it represents statuses that can be used by
 69     * anyone at any time.
 70     */
 71  
 72    /*
 73     * A few generic status codes that can be return anywhere. Their use should
 74     * be replaced with "real" status codes as soon as possible.  There are no
 75     * messages associated with these.
 76     *
 77     * Note that all severity codes aren't represented here, as they are not
 78     * all relevant for this level of simplicity.
 79     */
 80  # define LE_STS_WARNING                 (0 | LE_STATUS_SEVERITY_WARNING)
 81  # define LE_STS_SUCCESS                 (0 | LE_STATUS_SEVERITY_SUCCESS)
 82  # define LE_STS_ERROR                   (0 | LE_STATUS_SEVERITY_ERROR)
 83  # define LE_STS_FATAL_ERROR             (0 | LE_STATUS_SEVERITY_FATAL)
 84  
 85    /*
 86     * A few generic status codes for some common cases.  Note that they can
 87     * be used with other severities, as the application desires.
 88     */
 89  # define LE_STS_ALLOC_FAILURE           (1 | LE_STATUS_SEVERITY_FATAL)
 90  # define LE_STS_NOT_IMPLEMENTED         (2 | LE_STATUS_SEVERITY_ERROR)
 91  # define LE_STS_NOT_SUPPORTED           (3 | LE_STATUS_SEVERITY_WARNING)
 92  # define LE_STS_INVALID_PARAMETER       (4 | LE_STATUS_SEVERITY_ERROR)
 93  
 94    /*
 95     * For processing errors further than just returning a status code,
 96     * storage and functions to register and retrieve messages are needed.
 97     * The storage structure is opaque.
 98     */
 99  
100    typedef struct LE_messages_st LE_messages_t;
101  
102    LE_STATUS LE_new_status_messages(LE_messages_t **mdata);
103    LE_STATUS LE_free_status_messages(LE_messages_t **mdata);
104    LE_STATUS LE_register_status_unit(LE_messages_t *mdata, LE_STATUS sts,
105                                      const char *name);
106    LE_STATUS LE_register_status_message(LE_messages_t *mdata, LE_STATUS sts,
107                                         const char *identity, const char *text);
108  
109    /*
110     * Formats the text for the message given by |sts|.  The message text
111     * is formatted like this:
112     *
113     * {prefix}:{unit}-{severity}-{identity}, {message-text}
114     *
115     * The {prefix} is:
116     *
117     * - for the severities ERROR, SEVERE and FATAL: error
118     * - for the severity WARNING: warning
119     * - for the severities SUCCESS and INFORMATION: note
120     *
121     * The {unit} is the unit identity, or "NOUNIT" if the unit name hasn't
122     * been registered.
123     *
124     * The {severity} is one character indicating the exact severity:
125     *
126     * - W for WARNING
127     * - S for SUCCESS
128     * - E for ERROR
129     * - I for INFORMATION
130     * - F for SEVERE or FATAL
131     *
132     * The {identity} is the registered message identity, or "NOMSG" if the
133     * message identity hasn't been registered.
134     *
135     * The {message-text} is the registered message text, or "Status=0x{sts-hex}"
136     * with {sts-hexh} replaced with the hexadecimal rendition of |sts|
137     */
138    LE_STATUS LE_get_status_text(const LE_messages_t *mdata, LE_STATUS sts,
139                                 char *buf, size_t *buflen, size_t bufsize);
140  
141    /*
142     * Utility to print messages, with additional text for each message.
143     * The data for the messages are passed with the |message_vector|, and
144     * may include additional text for each message in that vector.
145     *
146     * Each message in the message vector is passed to LE_get_status_text(),
147     * and the result is formatted like this:
148     *
149     * 1st message:
150     *
151     * {status-text}
152     *   {additional text}
153     *
154     * 2nd..nth message
155     *
156     * -{status-text}
157     *   {additional text}
158     *
159     * {status-text} is the text provided by LE_get_status_text(), and
160     * {additional-text} is the concatenation of all the additional texts
161     * in the message vector.
162     *
163     * |action| is an optional routine that is called for each message being
164     * printed.  If it is NULL or returns true, LE_print_status will proceed
165     * with printing the message to stderr, otherwise it will not.
166     */
167    typedef struct LE_message_vector_st {
168      LE_STATUS sts;
169      size_t additional_text_count;
170      const char **additional_text;
171    } LE_message_vector_t;
172    LE_STATUS LE_print_status(const LE_messages_t *mdata,
173                              size_t message_vector_count,
174                              LE_message_vector_t *message_vector,
175                              _Bool (*action)(const char *message));
176  
177  # ifdef __cplusplus
178  }
179  # endif
180  
181  #endif