cstr.h (5242B)
1 /* Copyright (C) 2013-2023, 2025 Vincent Forest (vaplv@free.fr) 2 * 3 * The RSys library is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published 5 * by the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * The RSys library is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #ifndef CSTR_H 17 #define CSTR_H 18 19 #include "rsys.h" 20 21 #include "math.h" 22 23 #include <errno.h> 24 #include <float.h> 25 #include <limits.h> 26 #include <stdlib.h> 27 28 enum size_unit { 29 SIZE_BYTE = BIT(0), 30 SIZE_KBYTE = BIT(1), 31 SIZE_MBYTE = BIT(2), 32 SIZE_GBYTE = BIT(3), 33 SIZE_TBYTE = BIT(4), 34 SIZE_ALL = -1 35 }; 36 37 static INLINE res_T 38 cstr_to_double(const char* str, double* dst) 39 { 40 char* end; 41 ASSERT(dst); 42 if(!str) return RES_BAD_ARG; 43 *dst = strtod(str, &end); 44 if(end == str) 45 return RES_BAD_ARG; 46 for(;*end != '\0'; ++end) { 47 if(*end != ' ' && *end != '\t') 48 return RES_BAD_ARG; 49 } 50 return RES_OK; 51 } 52 53 static INLINE res_T 54 cstr_to_float(const char* str, float* dst) 55 { 56 double dbl; 57 double tmp; 58 res_T res; 59 ASSERT(dst); 60 res = cstr_to_double(str, &dbl); 61 if(res != RES_OK) return res; 62 tmp = fabs(dbl); 63 if(tmp != INF && tmp > 0.0 && (tmp < FLT_MIN || tmp > FLT_MAX)) 64 return RES_BAD_ARG; 65 *dst = (float)dbl; 66 return RES_OK; 67 } 68 69 static INLINE res_T 70 cstr_to_long(const char* str, long* dst) 71 { 72 char* end; 73 ASSERT(dst); 74 if(!str) return RES_BAD_ARG; 75 errno = 0; 76 *dst = strtol(str, &end, 10/* base */); 77 if(end == str || errno == ERANGE) 78 return RES_BAD_ARG; 79 for(;*end != '\0'; ++end) { 80 if(*end != ' ' && *end != '\t') 81 return RES_BAD_ARG; 82 } 83 return RES_OK; 84 } 85 86 static INLINE res_T 87 cstr_to_int(const char* str, int* dst) 88 { 89 long l; 90 res_T res; 91 ASSERT(dst); 92 res = cstr_to_long(str, &l); 93 if(res != RES_OK) 94 return res; 95 if(l > INT_MAX || l < INT_MIN) 96 return RES_BAD_ARG; 97 *dst = (int)l; 98 return RES_OK; 99 } 100 101 static INLINE res_T 102 cstr_to_ulong(const char* str, unsigned long* dst) 103 { 104 char* end; 105 ASSERT(dst); 106 if (!str) return RES_BAD_ARG; 107 errno = 0; 108 *dst = strtoul(str, &end, 10/* base */); 109 if(end == str || errno == ERANGE) 110 return RES_BAD_ARG; 111 ASSERT(errno == 0); 112 for(; *end != '\0'; ++end) { 113 if(*end != ' ' && *end != '\t') 114 return RES_BAD_ARG; 115 } 116 return RES_OK; 117 } 118 119 static INLINE res_T 120 cstr_to_uint(const char* str, unsigned* dst) 121 { 122 res_T res; 123 ASSERT(dst); 124 #if UINT_MAX == ULONG_MAX 125 { 126 unsigned long l; 127 res = cstr_to_ulong(str, &l); 128 if(res != RES_OK) return res; 129 *dst = (unsigned)l; 130 } 131 #else /* UINT_MAX < ULONG_MAX */ 132 { 133 long l; 134 res = cstr_to_long(str, &l); 135 if(res != RES_OK) return res; 136 if(l > UINT_MAX) return RES_BAD_ARG; 137 *dst = (unsigned)l; 138 } 139 #endif 140 return RES_OK; 141 } 142 143 static INLINE const char* 144 res_to_cstr(const res_T res) 145 { 146 const char* cstr = NULL; 147 switch(res) { 148 case RES_OK: cstr = "Success"; break; 149 case RES_BAD_ARG: cstr = "Invalid argument"; break; 150 case RES_MEM_ERR: cstr = "Could not allocate memory"; break; 151 case RES_IO_ERR: cstr = "Input/Ouput error"; break; 152 case RES_UNKNOWN_ERR: cstr = "Unknown error"; break; 153 case RES_BAD_OP: cstr = "Invalid operation"; break; 154 case RES_EOF: cstr = "Reached end of file"; break; 155 default: FATAL("Ureachable code.\n"); break; 156 } 157 return cstr; 158 } 159 160 BEGIN_DECLS 161 162 /* Parse a string representing a list whose its elements are separated by the 163 * 'delimeter' char. The functor 'parse_element' is invoked on each element of 164 * the list. If it notifies an error, i.e. if the parsing of an element failed, 165 * the overall parsing is instantly stopped and the error is returned to the 166 * caller */ 167 RSYS_API res_T 168 cstr_parse_list 169 (const char* str, 170 const char delimiter, 171 res_T (*parse_element)(const char* elmt, void* ctx), 172 void* ctx); /* User defined data sent to 'parse_element' */ 173 174 /* Convert a string "A:B:C:D:E:F" in a list of { A, B, C, D, E, F }. ':' can be 175 * any user defined character */ 176 RSYS_API res_T 177 cstr_to_list_double 178 (const char* str, 179 const char delimiter, 180 double dst[], /* May be NULL */ 181 size_t* length, /* May be NULL. Length of the filled list */ 182 const size_t max_length); /* Maximum size of dst */ 183 184 RSYS_API res_T 185 cstr_to_list_float 186 (const char* str, 187 const char delimiter, 188 float dst[], /* May be NULL */ 189 size_t* length, /* May be NULL. Length of the filled list */ 190 const size_t max_length); /* Maximum size of dst */ 191 192 RSYS_API res_T 193 cstr_to_list_uint 194 (const char* str, 195 const char delimiter, 196 unsigned dst[], 197 size_t* length, 198 const size_t max_length); 199 200 RSYS_API void 201 size_to_cstr 202 (const size_t size, 203 const int flag, /* Combination of size_unit */ 204 size_t* real_cstr_len, /* May be NULL (does not handle null char) */ 205 char* cstr, /* May be NULL */ 206 const size_t sizeof_cstr); /* Include null char */ 207 208 END_DECLS 209 210 #endif /* CSTR_H */