1 /***************************************************************************************************
2 
3   Zyan Core Library (Zycore-C)
4 
5   Original Author : Florian Bernd, Joel Hoener
6 
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24 
25 ***************************************************************************************************/
26 
27 /**
28  * @file
29  * @brief   Provides a simple LibC abstraction and fallback routines.
30  */
31 
32 #ifndef ZYCORE_LIBC_H
33 #define ZYCORE_LIBC_H
34 
35 #ifndef ZYAN_CUSTOM_LIBC
36 
37 // Include a custom LibC header and define `ZYAN_CUSTOM_LIBC` to provide your own LibC
38 // replacement functions
39 
40 #ifndef ZYAN_NO_LIBC
41 
42 /* ============================================================================================== */
43 /* LibC is available                                                                              */
44 /* ============================================================================================== */
45 
46 /* ---------------------------------------------------------------------------------------------- */
47 /* errno.h                                                                                        */
48 /* ---------------------------------------------------------------------------------------------- */
49 
50 #include <errno.h>
51 
52 #define ZYAN_ERRNO  errno
53 
54 /* ---------------------------------------------------------------------------------------------- */
55 /* stdarg.h                                                                                       */
56 /* ---------------------------------------------------------------------------------------------- */
57 
58 #include <stdarg.h>
59 
60 /**
61  * @brief   Defines the `ZyanVAList` datatype.
62  */
63 typedef va_list ZyanVAList;
64 
65 #define ZYAN_VA_START               va_start
66 #define ZYAN_VA_ARG                 va_arg
67 #define ZYAN_VA_END                 va_end
68 #define ZYAN_VA_COPY(dest, source)  va_copy((dest), (source))
69 
70 /* ---------------------------------------------------------------------------------------------- */
71 /* stdio.h                                                                                        */
72 /* ---------------------------------------------------------------------------------------------- */
73 
74 #include <stdio.h>
75 
76 #define ZYAN_FPUTS      fputs
77 #define ZYAN_FPUTC      fputc
78 #define ZYAN_FPRINTF    fprintf
79 #define ZYAN_PRINTF     printf
80 #define ZYAN_PUTC       putc
81 #define ZYAN_PUTS       puts
82 #define ZYAN_SCANF      scanf
83 #define ZYAN_SSCANF     sscanf
84 #define ZYAN_VSNPRINTF  vsnprintf
85 
86 /**
87  * @brief   Defines the `ZyanFile` datatype.
88  */
89 typedef FILE ZyanFile;
90 
91 #define ZYAN_STDIN      stdin
92 #define ZYAN_STDOUT     stdout
93 #define ZYAN_STDERR     stderr
94 
95 /* ---------------------------------------------------------------------------------------------- */
96 /* stdlib.h                                                                                       */
97 /* ---------------------------------------------------------------------------------------------- */
98 
99 #include <stdlib.h>
100 #define ZYAN_CALLOC     calloc
101 #define ZYAN_FREE       free
102 #define ZYAN_MALLOC     malloc
103 #define ZYAN_REALLOC    realloc
104 
105 /* ---------------------------------------------------------------------------------------------- */
106 /* string.h                                                                                       */
107 /* ---------------------------------------------------------------------------------------------- */
108 
109 #include <string.h>
110 #define ZYAN_MEMCHR     memchr
111 #define ZYAN_MEMCMP     memcmp
112 #define ZYAN_MEMCPY     memcpy
113 #define ZYAN_MEMMOVE    memmove
114 #define ZYAN_MEMSET     memset
115 #define ZYAN_STRCAT     strcat
116 #define ZYAN_STRCHR     strchr
117 #define ZYAN_STRCMP     strcmp
118 #define ZYAN_STRCOLL    strcoll
119 #define ZYAN_STRCPY     strcpy
120 #define ZYAN_STRCSPN    strcspn
121 #define ZYAN_STRLEN     strlen
122 #define ZYAN_STRNCAT    strncat
123 #define ZYAN_STRNCMP    strncmp
124 #define ZYAN_STRNCPY    strncpy
125 #define ZYAN_STRPBRK    strpbrk
126 #define ZYAN_STRRCHR    strrchr
127 #define ZYAN_STRSPN     strspn
128 #define ZYAN_STRSTR     strstr
129 #define ZYAN_STRTOK     strtok
130 #define ZYAN_STRXFRM    strxfrm
131 
132 /* ---------------------------------------------------------------------------------------------- */
133 
134 #else  // if ZYAN_NO_LIBC
135 
136 /* ============================================================================================== */
137 /* No LibC available, use our own functions                                                       */
138 /* ============================================================================================== */
139 
140 #include <Zycore/Defines.h>
141 #include <Zycore/Types.h>
142 
143 /*
144  * These implementations are by no means optimized and will be outperformed by pretty much any
145  * libc implementation out there. We do not aim towards providing competetive implementations here,
146  * but towards providing a last resort fallback for environments without a working libc.
147  */
148 
149 /* ---------------------------------------------------------------------------------------------- */
150 /* stdarg.h                                                                                       */
151 /* ---------------------------------------------------------------------------------------------- */
152 
153 #if defined(ZYAN_MSVC) || defined(ZYAN_ICC)
154 
155 /**
156  * @brief   Defines the `ZyanVAList` datatype.
157  */
158 typedef char* ZyanVAList;
159 
160 #   define ZYAN_VA_START __crt_va_start
161 #   define ZYAN_VA_ARG   __crt_va_arg
162 #   define ZYAN_VA_END   __crt_va_end
163 #   define ZYAN_VA_COPY(destination, source) ((destination) = (source))
164 
165 #elif defined(ZYAN_GNUC)
166 
167 /**
168  * @brief   Defines the `ZyanVAList` datatype.
169  */
170 typedef __builtin_va_list  ZyanVAList;
171 
172 #   define ZYAN_VA_START(v, l)  __builtin_va_start(v, l)
173 #   define ZYAN_VA_END(v)       __builtin_va_end(v)
174 #   define ZYAN_VA_ARG(v, l)    __builtin_va_arg(v, l)
175 #   define ZYAN_VA_COPY(d, s)   __builtin_va_copy(d, s)
176 
177 #else
178 #   error "Unsupported compiler for no-libc mode."
179 #endif
180 
181 /* ---------------------------------------------------------------------------------------------- */
182 /* stdio.h                                                                                        */
183 /* ---------------------------------------------------------------------------------------------- */
184 
185 // ZYAN_INLINE int ZYAN_VSNPRINTF (char* const buffer, ZyanUSize const count,
186 //     char const* const format, ZyanVAList args)
187 // {
188 //      // We cant provide a fallback implementation for this function
189 //     ZYAN_UNUSED(buffer);
190 //     ZYAN_UNUSED(count);
191 //     ZYAN_UNUSED(format);
192 //     ZYAN_UNUSED(args);
193 //     return ZYAN_NULL;
194 // }
195 
196 /* ---------------------------------------------------------------------------------------------- */
197 /* stdlib.h                                                                                       */
198 /* ---------------------------------------------------------------------------------------------- */
199 
200 // ZYAN_INLINE void* ZYAN_CALLOC(ZyanUSize nitems, ZyanUSize size)
201 // {
202 //      // We cant provide a fallback implementation for this function
203 //     ZYAN_UNUSED(nitems);
204 //     ZYAN_UNUSED(size);
205 //     return ZYAN_NULL;
206 // }
207 //
208 // ZYAN_INLINE void ZYAN_FREE(void *p)
209 // {
210 //      // We cant provide a fallback implementation for this function
211 //     ZYAN_UNUSED(p);
212 // }
213 //
214 // ZYAN_INLINE void* ZYAN_MALLOC(ZyanUSize n)
215 // {
216 //     // We cant provide a fallback implementation for this function
217 //     ZYAN_UNUSED(n);
218 //     return ZYAN_NULL;
219 // }
220 //
221 // ZYAN_INLINE void* ZYAN_REALLOC(void* p, ZyanUSize n)
222 // {
223 //      // We cant provide a fallback implementation for this function
224 //     ZYAN_UNUSED(p);
225 //     ZYAN_UNUSED(n);
226 //     return ZYAN_NULL;
227 // }
228 
229 /* ---------------------------------------------------------------------------------------------- */
230 /* string.h                                                                                       */
231 /* ---------------------------------------------------------------------------------------------- */
232 
ZYAN_MEMCHR(const void * str,int c,ZyanUSize n)233 ZYAN_INLINE void* ZYAN_MEMCHR(const void* str, int c, ZyanUSize n)
234 {
235     const ZyanU8* p = (ZyanU8*)str;
236     while (n--)
237     {
238         if (*p != (ZyanU8)c)
239         {
240             p++;
241         } else
242         {
243             return (void*)p;
244         }
245     }
246     return 0;
247 }
248 
ZYAN_MEMCMP(const void * s1,const void * s2,ZyanUSize n)249 ZYAN_INLINE int ZYAN_MEMCMP(const void* s1, const void* s2, ZyanUSize n)
250 {
251     const ZyanU8* p1 = s1, *p2 = s2;
252     while (n--)
253     {
254         if (*p1 != *p2)
255         {
256             return *p1 - *p2;
257         }
258         p1++, p2++;
259     }
260     return 0;
261 }
262 
ZYAN_MEMCPY(void * dst,const void * src,ZyanUSize n)263 ZYAN_INLINE void* ZYAN_MEMCPY(void* dst, const void* src, ZyanUSize n)
264 {
265     volatile ZyanU8* dp = dst;
266     const ZyanU8* sp = src;
267     while (n--)
268     {
269         *dp++ = *sp++;
270     }
271     return dst;
272 }
273 
ZYAN_MEMMOVE(void * dst,const void * src,ZyanUSize n)274 ZYAN_INLINE void* ZYAN_MEMMOVE(void* dst, const void* src, ZyanUSize n)
275 {
276     volatile ZyanU8* pd = dst;
277     const ZyanU8* ps = src;
278     if (ps < pd)
279     {
280         for (pd += n, ps += n; n--;)
281         {
282             *--pd = *--ps;
283         }
284     } else
285     {
286         while (n--)
287         {
288             *pd++ = *ps++;
289         }
290     }
291     return dst;
292 }
293 
ZYAN_MEMSET(void * dst,int val,ZyanUSize n)294 ZYAN_INLINE void* ZYAN_MEMSET(void* dst, int val, ZyanUSize n)
295 {
296     volatile ZyanU8* p = dst;
297     while (n--)
298     {
299         *p++ = (unsigned char)val;
300     }
301     return dst;
302 }
303 
ZYAN_STRCAT(char * dest,const char * src)304 ZYAN_INLINE char* ZYAN_STRCAT(char* dest, const char* src)
305 {
306     char* ret = dest;
307     while (*dest)
308     {
309         dest++;
310     }
311     while ((*dest++ = *src++));
312     return ret;
313 }
314 
ZYAN_STRCHR(const char * s,int c)315 ZYAN_INLINE char* ZYAN_STRCHR(const char* s, int c)
316 {
317     while (*s != (char)c)
318     {
319         if (!*s++)
320         {
321             return 0;
322         }
323     }
324     return (char*)s;
325 }
326 
ZYAN_STRCMP(const char * s1,const char * s2)327 ZYAN_INLINE int ZYAN_STRCMP(const char* s1, const char* s2)
328 {
329     while (*s1 && (*s1 == *s2))
330     {
331         s1++, s2++;
332     }
333     return *(const ZyanU8*)s1 - *(const ZyanU8*)s2;
334 }
335 
ZYAN_STRCOLL(const char * s1,const char * s2)336 ZYAN_INLINE int ZYAN_STRCOLL(const char *s1, const char *s2)
337 {
338     // TODO: Implement
339 
340     ZYAN_UNUSED(s1);
341     ZYAN_UNUSED(s2);
342 
343     return 0;
344 }
345 
ZYAN_STRCPY(char * dest,const char * src)346 ZYAN_INLINE char* ZYAN_STRCPY(char* dest, const char* src)
347 {
348     char* ret = dest;
349     while ((*dest++ = *src++));
350     return ret;
351 }
352 
ZYAN_STRCSPN(const char * s1,const char * s2)353 ZYAN_INLINE ZyanUSize ZYAN_STRCSPN(const char *s1, const char *s2)
354 {
355     ZyanUSize ret = 0;
356     while (*s1)
357     {
358         if (ZYAN_STRCHR(s2, *s1))
359         {
360             return ret;
361         }
362         s1++, ret++;
363     }
364     return ret;
365 }
366 
ZYAN_STRLEN(const char * str)367 ZYAN_INLINE ZyanUSize ZYAN_STRLEN(const char* str)
368 {
369     const char* p = str;
370     while (*str)
371     {
372         ++str;
373     }
374     return str - p;
375 }
376 
ZYAN_STRNCAT(char * dest,const char * src,ZyanUSize n)377 ZYAN_INLINE char* ZYAN_STRNCAT(char* dest, const char* src, ZyanUSize n)
378 {
379     char* ret = dest;
380     while (*dest)
381     {
382         dest++;
383     }
384     while (n--)
385     {
386         if (!(*dest++ = *src++))
387         {
388             return ret;
389         }
390     }
391     *dest = 0;
392     return ret;
393 }
394 
ZYAN_STRNCMP(const char * s1,const char * s2,ZyanUSize n)395 ZYAN_INLINE int ZYAN_STRNCMP(const char* s1, const char* s2, ZyanUSize n)
396 {
397     while (n--)
398     {
399         if (*s1++ != *s2++)
400         {
401             return *(unsigned char*)(s1 - 1) - *(unsigned char*)(s2 - 1);
402         }
403     }
404     return 0;
405 }
406 
ZYAN_STRNCPY(char * dest,const char * src,ZyanUSize n)407 ZYAN_INLINE char* ZYAN_STRNCPY(char* dest, const char* src, ZyanUSize n)
408 {
409     char* ret = dest;
410     do
411     {
412         if (!n--)
413         {
414             return ret;
415         }
416     } while ((*dest++ = *src++));
417     while (n--)
418     {
419         *dest++ = 0;
420     }
421     return ret;
422 }
423 
ZYAN_STRPBRK(const char * s1,const char * s2)424 ZYAN_INLINE char* ZYAN_STRPBRK(const char* s1, const char* s2)
425 {
426     while (*s1)
427     {
428         if(ZYAN_STRCHR(s2, *s1++))
429         {
430             return (char*)--s1;
431         }
432     }
433     return 0;
434 }
435 
ZYAN_STRRCHR(const char * s,int c)436 ZYAN_INLINE char* ZYAN_STRRCHR(const char* s, int c)
437 {
438     char* ret = 0;
439     do
440     {
441         if (*s == (char)c)
442         {
443             ret = (char*)s;
444         }
445     } while (*s++);
446     return ret;
447 }
448 
ZYAN_STRSPN(const char * s1,const char * s2)449 ZYAN_INLINE ZyanUSize ZYAN_STRSPN(const char* s1, const char* s2)
450 {
451     ZyanUSize ret = 0;
452     while (*s1 && ZYAN_STRCHR(s2, *s1++))
453     {
454         ret++;
455     }
456     return ret;
457 }
458 
ZYAN_STRSTR(const char * s1,const char * s2)459 ZYAN_INLINE char* ZYAN_STRSTR(const char* s1, const char* s2)
460 {
461     const ZyanUSize n = ZYAN_STRLEN(s2);
462     while (*s1)
463     {
464         if (!ZYAN_MEMCMP(s1++, s2, n))
465         {
466             return (char*)(s1 - 1);
467         }
468     }
469     return 0;
470 }
471 
ZYAN_STRTOK(char * str,const char * delim)472 ZYAN_INLINE char* ZYAN_STRTOK(char* str, const char* delim)
473 {
474     static char* p = 0;
475     if (str)
476     {
477         p = str;
478     } else
479     if (!p)
480     {
481         return 0;
482     }
483     str = p + ZYAN_STRSPN(p, delim);
484     p = str + ZYAN_STRCSPN(str, delim);
485     if (p == str)
486     {
487         return p = 0;
488     }
489     p = *p ? *p = 0, p + 1 : 0;
490     return str;
491 }
492 
ZYAN_STRXFRM(char * dest,const char * src,ZyanUSize n)493 ZYAN_INLINE ZyanUSize ZYAN_STRXFRM(char* dest, const char* src, ZyanUSize n)
494 {
495     const ZyanUSize n2 = ZYAN_STRLEN(src);
496     if (n > n2)
497     {
498         ZYAN_STRCPY(dest, src);
499     }
500     return n2;
501 }
502 
503 /* ---------------------------------------------------------------------------------------------- */
504 
505 #endif
506 
507 #endif
508 
509 /* ============================================================================================== */
510 
511 #endif /* ZYCORE_LIBC_H */
512