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