1 /*@ Implementation of code.h: error (number) handling.
2 *
3 * Copyright (c) 2017 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
4 * SPDX-License-Identifier: ISC
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 #undef su_FILE
19 #define su_FILE su_core_errors
20 #define su_SOURCE
21 #define su_SOURCE_CORE_ERRORS
22
23 #include "su/cs.h"
24 #include "su/icodec.h"
25
26 #include "su/code.h"
27 #include "su/code-in.h"
28
29 struct a_corerr_map{
30 u32 cem_hash; /* Hash of name */
31 u32 cem_nameoff; /* Into a_corerr_names[] */
32 u32 cem_docoff; /* Into a_corerr_docs[] */
33 s32 cem_errno; /* OS errno value for this one */
34 };
35
36 /* Include the constant su-make-errors.sh output */
37 #include "su/gen-errors.h" /* $(SU_SRCDIR) */
38
39 /* And these come in via su/config.h (config-time su-make-errors.sh output) */
40 static su__ERR_NUMBER_TYPE const a_corerr_no2mapoff[][2] = {
41 #undef a_X
42 #define a_X(N,I) {N,I},
43 su__ERR_NUMBER_TO_MAPOFF
44 #undef a_X
45 };
46
47 /* Find the descriptive mapping of an error number, or _ERR_INVAL */
48 static struct a_corerr_map const *a_corerr_map_from_no(s32 eno);
49
50 static struct a_corerr_map const *
a_corerr_map_from_no(s32 eno)51 a_corerr_map_from_no(s32 eno){
52 s32 ecmp;
53 uz asz;
54 su__ERR_NUMBER_TYPE const (*adat)[2], (*tmp)[2];
55 struct a_corerr_map const *cemp;
56 NYD2_IN;
57
58 cemp = &a_corerr_map[su__ERR_NUMBER_VOIDOFF];
59
60 if(UCMP(z, su_ABS(eno), <=, S(su__ERR_NUMBER_TYPE,-1))){
61 for(adat = a_corerr_no2mapoff, asz = su_NELEM(a_corerr_no2mapoff);
62 asz != 0; asz >>= 1){
63 tmp = &adat[asz >> 1];
64 if((ecmp = (s32)(S(su__ERR_NUMBER_TYPE,eno) - (*tmp)[0])) == 0){
65 cemp = &a_corerr_map[(*tmp)[1]];
66 break;
67 }
68 if(ecmp > 0){
69 adat = &tmp[1];
70 --asz;
71 }
72 }
73 }
74 NYD2_OU;
75 return cemp;
76 }
77
78 char const *
su_err_doc(s32 eno)79 su_err_doc(s32 eno){
80 char const *rv;
81 struct a_corerr_map const *cemp;
82 NYD2_IN;
83
84 cemp = a_corerr_map_from_no(eno);
85 rv = (
86 #ifdef su_HAVE_DOCSTRINGS
87 !su_state_has(su_STATE_REPRODUCIBLE)
88 ? &a_corerr_docs[cemp->cem_docoff] :
89 #endif
90 &a_corerr_names[cemp->cem_nameoff]);
91
92 NYD2_OU;
93 return rv;
94 }
95
96 char const *
su_err_name(s32 eno)97 su_err_name(s32 eno){
98 char const *rv;
99 struct a_corerr_map const *cemp;
100 NYD2_IN;
101
102 cemp = a_corerr_map_from_no(eno);
103 rv = &a_corerr_names[cemp->cem_nameoff];
104 NYD2_OU;
105 return rv;
106 }
107
108 s32
su_err_from_name(char const * name)109 su_err_from_name(char const *name){
110 struct a_corerr_map const *cemp;
111 u32 hash, i, j, x;
112 s32 rv;
113 NYD2_IN;
114
115 hash = su_cs_hash(name) & U32_MAX;
116
117 for(i = hash % a_CORERR_REV_PRIME, j = 0; j <= a_CORERR_REV_LONGEST; ++j){
118 if((x = a_corerr_revmap[i]) == a_CORERR_REV_ILL)
119 break;
120
121 cemp = &a_corerr_map[x];
122 if(cemp->cem_hash == hash &&
123 !su_cs_cmp(&a_corerr_names[cemp->cem_nameoff], name)){
124 rv = cemp->cem_errno;
125 goto jleave;
126 }
127
128 if(++i == a_CORERR_REV_PRIME){
129 #ifdef a_CORERR_REV_WRAPAROUND
130 i = 0;
131 #else
132 break;
133 #endif
134 }
135 }
136
137 /* Have not found it. But wait, it could be that the user did, e.g.,
138 * eval echo \$^ERR-$: \$^ERRDOC-$!: \$^ERRNAME-$! */
139 if((su_idec_s32_cp(&rv, name, 0, NIL) &
140 (su_IDEC_STATE_EMASK | su_IDEC_STATE_CONSUMED)
141 ) == su_IDEC_STATE_CONSUMED){
142 cemp = a_corerr_map_from_no(rv);
143 rv = cemp->cem_errno;
144 goto jleave;
145 }
146
147 rv = a_corerr_map[su__ERR_NUMBER_VOIDOFF].cem_errno;
148 jleave:
149 NYD2_OU;
150 return rv;
151 }
152
153 #include "su/code-ou.h"
154 /* s-it-mode */
155