1 /* Portability header file for the CADO project
2 
3 Copyright 2013 Pierrick Gaudry, Alexander Kruppa,
4                Emmanuel Thome, Paul Zimmermann
5 
6 This file is part of the CADO project.
7 
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12 
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 Lesser General Public License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 
22 */
23 
24 /* This header file defines macros (and perhaps static functions) to improve
25  * portability of the CADO code. They aim to provide a wrapper for some C99
26  * and POSIX functionality for systems that lack those.
27  */
28 
29 #ifndef CADO_PORTABILITY_H_
30 #define CADO_PORTABILITY_H_
31 
32 #ifndef CADO_CONFIG_H_
33 #error cado_config.h must be included before portability.h
34 #endif
35 
36 #include "macros.h"
37 
38 #ifndef HAVE_STRDUP/*{{{*/
39 #include <stdlib.h>
40 #include <string.h>
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
strdup(const char * const s)44 static inline char * strdup(const char * const s)
45 {
46     const size_t size = strlen(s) + 1;
47     char * const r = (char *) malloc(size * sizeof(char));
48     if (r != NULL)
49         memcpy(r, s, size);
50     return r;
51 }
52 #ifdef __cplusplus
53 }
54 #endif
55 #endif /* HAVE_STRDUP *//*}}}*/
56 
57 #ifndef HAVE_STRNDUP/*{{{*/
58 /* strndup is posix-2008. providing a workalike is very easy */
59 #include <stdlib.h>
60 #include <string.h>
61 #ifdef __cplusplus
62 extern "C" {
63 #endif
strndup(const char * const a,const size_t n)64 static inline char * strndup(const char * const a, const size_t n)
65 {
66     const size_t l = strlen(a);
67     const size_t size = (l < n ? l : n) + 1;
68     char * const r = (char *) malloc(size * sizeof(char));
69     if (r != NULL) {
70         memcpy(r, a, size);
71         r[size] = '\0';
72     }
73     return r;
74 }
75 #ifdef __cplusplus
76 }
77 #endif
78 #endif /* HAVE_STRNDUP *//*}}}*/
79 
80 #ifndef HAVE_STRNLEN/*{{{*/
81 /* strnlen is posix-2008. providing a workalike is very easy */
82 #ifdef __cplusplus
83 extern "C" {
84 #endif
strnlen(const char * s,size_t maxlen)85 static inline size_t strnlen (const char *s, size_t maxlen)
86 {
87   size_t ret = 0;
88   for (; ret < maxlen && *s; s++)
89     ret++;
90   return ret;
91 }
92 #ifdef __cplusplus
93 }
94 #endif
95 #endif/*}}}*/
96 
97 #ifndef HAVE_STRLCPY/*{{{*/
98 /* strlcpy is a bsd specificity, but we find it quite handy */
99 
100 /*	$OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $	*/
101 
102 /*
103  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
104  *
105  * Permission to use, copy, modify, and distribute this software for any
106  * purpose with or without fee is hereby granted, provided that the above
107  * copyright notice and this permission notice appear in all copies.
108  *
109  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
110  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
111  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
112  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
113  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
114  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
115  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
116  */
117 
118 #include <sys/types.h>
119 #include <string.h>
120 
121 #ifdef __cplusplus
122 extern "C" {
123 #endif
124 /*
125  * Copy src to string dst of size siz.  At most siz-1 characters
126  * will be copied.  Always NUL terminates (unless siz == 0).
127  * Returns strlen(src); if retval >= siz, truncation occurred.
128  */
129 static inline size_t strlcpy(char *dst, const char *src, size_t size) ATTRIBUTE((__warn_unused_result__));
130 static inline size_t
131 strlcpy(char *dst, const char *src, size_t siz) ATTRIBUTE_WARN_UNUSED_RESULT;
132 static inline size_t
strlcpy(char * dst,const char * src,size_t siz)133 strlcpy(char *dst, const char *src, size_t siz)
134 {
135 	char *d = dst;
136 	const char *s = src;
137 	size_t n = siz;
138 
139 	/* Copy as many bytes as will fit */
140 	if (n != 0) {
141 		while (--n != 0) {
142 			if ((*d++ = *s++) == '\0')
143 				break;
144 		}
145 	}
146 
147 	/* Not enough room in dst, add NUL and traverse rest of src */
148 	if (n == 0) {
149 		if (siz != 0)
150 			*d = '\0';		/* NUL-terminate dst */
151 		while (*s++)
152 			;
153 	}
154 
155 	return(s - src - 1);	/* count does not include NUL */
156 }
157 #ifdef __cplusplus
158 }
159 #endif
160 #endif/*}}}*/
161 
162 #ifndef HAVE_STRLCAT/*{{{*/
163 /* strlcat is a bsd specificity, but we find it quite handy */
164 
165 /*	$OpenBSD: strlcat.c,v 1.19 2019/01/25 00:19:25 millert Exp $	*/
166 
167 /*
168  * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
169  *
170  * Permission to use, copy, modify, and distribute this software for any
171  * purpose with or without fee is hereby granted, provided that the above
172  * copyright notice and this permission notice appear in all copies.
173  *
174  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
175  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
176  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
177  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
178  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
179  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
180  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
181  */
182 
183 #include <sys/types.h>
184 #include <string.h>
185 
186 #ifdef __cplusplus
187 extern "C" {
188 #endif
189 /*
190  * Appends src to string dst of size dsize (unlike strncat, dsize is the
191  * full size of dst, not space left).  At most dsize-1 characters
192  * will be copied.  Always NUL terminates (unless dsize <= strlen(dst)).
193  * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
194  * If retval >= dsize, truncation occurred.
195  */
196 static inline size_t
197 strlcat(char *dst, const char *src, size_t dsize) ATTRIBUTE_WARN_UNUSED_RESULT;
198 static inline size_t
strlcat(char * dst,const char * src,size_t dsize)199 strlcat(char *dst, const char *src, size_t dsize)
200 {
201 	const char *odst = dst;
202 	const char *osrc = src;
203 	size_t n = dsize;
204 	size_t dlen;
205 
206 	/* Find the end of dst and adjust bytes left but don't go past end. */
207 	while (n-- != 0 && *dst != '\0')
208 		dst++;
209 	dlen = dst - odst;
210 	n = dsize - dlen;
211 
212 	if (n-- == 0)
213 		return(dlen + strlen(src));
214 	while (*src != '\0') {
215 		if (n != 0) {
216 			*dst++ = *src;
217 			n--;
218 		}
219 		src++;
220 	}
221 	*dst = '\0';
222 
223 	return(dlen + (src - osrc));	/* count does not include NUL */
224 }
225 #ifdef __cplusplus
226 }
227 #endif
228 #endif/*}}}*/
229 
230 /* MS VS and MinGW use the MS RTL (called MSVCRT for MinGW) which does not
231  * know the "%zu" format, they use "%Iu" instead. On MinGW, we use wrapper
232  * functions that rewrite the %zu format accordingly, so the bulk of the
233  * code can continue to use C99 syntax.
234 
235  * FIXME: looks like it's a bit of a mess. MinGW, with
236  * __USE_MINGW_ANSI_STDIO, claims to provide C99 things. But from reading
237  * the commit logs, it's not completely clear that this holds for the
238  * full extent of functions we want; maybe it's only *printf, and not
239  * *scanf.
240 
241  * Second aspect (below), with C++, it seems that <cstdio> is sometimes
242  * #undef-ining printf, maybe to the point of thrashing the C99-compliant
243  * variants we've selected. Does that say that in the end we *have* to
244  * use substitutes for every call ?
245  */
246 
247 #ifdef HAVE_MINGW/*{{{*/
248 
249 #include <stdio.h>
250 
251 /* For C++, including cstdio too is mandatory. Not much because we want
252  * it, but because it does feel free to do things such as #undef fprintf,
253  * which of course will get in the way since we want these renamed
254  * (bear in mind that some side-effect may cause cstdio to be included
255  * well after this file, unless we want to be #include-order dependent).
256  */
257 #ifdef  __cplusplus
258 #include <cstdio>
259 #endif
260 
261 #include <stdarg.h>
262 #include <stdlib.h>
263 #include <string.h>
264 #include "macros.h"
265 
266 static inline const char *
subst_zu(const char * const s)267 subst_zu(const char * const s)
268 {
269     char * const r = strdup(s);
270     const char * const prisiz = "Iu";
271     const char * const priptrdiff = "Id";
272     const size_t l = strlen(r);
273     size_t i;
274 
275     ASSERT_ALWAYS(strlen(prisiz) == 2);
276     ASSERT_ALWAYS(strlen(priptrdiff) == 2);
277     ASSERT_ALWAYS(r != NULL);
278     for (i = 0; i + 2 < l; i++)
279         if (r[i] == '%' && r[i+1] == 'z' && r[i+2] == 'u') {
280             r[i+1] = prisiz[0];
281             r[i+2] = prisiz[1];
282         } else if (r[i] == '%' && r[i+1] == 'z' && r[i+2] == 'd') {
283             r[i+1] = priptrdiff[0];
284             r[i+2] = priptrdiff[1];
285         } else if (r[i] == '%' && r[i+1] == 't' && r[i+2] == 'd') {
286             r[i+1] = priptrdiff[0];
287             r[i+2] = priptrdiff[1];
288         }
289     return r;
290 }
291 
292 static inline int
scanf_subst_zu(const char * const format,...)293 scanf_subst_zu (const char * const format, ...)
294 {
295   va_list ap;
296   const char * const subst_format = subst_zu (format);
297   int r;
298 
299   va_start (ap, format);
300   r = vscanf (subst_format, ap);
301   free ((void *)subst_format);
302   va_end (ap);
303   return r;
304 }
305 
306 static inline int
fscanf_subst_zu(FILE * const stream,const char * const format,...)307 fscanf_subst_zu (FILE * const stream, const char * const format, ...)
308 {
309   va_list ap;
310   const char * const subst_format = subst_zu (format);
311   int r;
312 
313   va_start (ap, format);
314   r = vfscanf (stream, subst_format, ap);
315   free ((void *)subst_format);
316   va_end (ap);
317   return r;
318 }
319 
320 static inline int
sscanf_subst_zu(const char * const str,const char * const format,...)321 sscanf_subst_zu (const char * const str, const char * const format, ...)
322 {
323   va_list ap;
324   const char * const subst_format = subst_zu (format);
325   int r;
326 
327   va_start (ap, format);
328   r = vsscanf (str, subst_format, ap);
329   free ((void *)subst_format);
330   va_end (ap);
331   return r;
332 }
333 
334 #define scanf scanf_subst_zu
335 #define fscanf fscanf_subst_zu
336 #define sscanf sscanf_subst_zu
337 
338 static inline int
printf_subst_zu(const char * const format,...)339 printf_subst_zu (const char * const format, ...)
340 {
341   va_list ap;
342   const char * const subst_format = subst_zu (format);
343   int r;
344 
345   va_start (ap, format);
346   r = vprintf (subst_format, ap);
347   free ((void *)subst_format);
348   va_end (ap);
349   return r;
350 }
351 
352 static inline int
fprintf_subst_zu(FILE * const stream,const char * const format,...)353 fprintf_subst_zu (FILE * const stream, const char * const format, ...)
354 {
355   va_list ap;
356   const char * const subst_format = subst_zu (format);
357   int r;
358 
359   va_start (ap, format);
360   r = vfprintf (stream, subst_format, ap);
361   free ((void *)subst_format);
362   va_end (ap);
363   return r;
364 }
365 
366 #define printf  printf_subst_zu
367 #define fprintf fprintf_subst_zu
368 
369 #endif /* ifdef HAVE_MINGW *//*}}}*/
370 
371 #ifndef HAVE_ASPRINTF/*{{{*/
372 /* Copied and improved from
373  * http://mingw-users.1079350.n2.nabble.com/Query-regarding-offered-alternative-to-asprintf-td6329481.html
374  */
375 #include <stdarg.h>
376 #include <stdio.h>
377 #include <stdlib.h>
378 #ifdef __cplusplus
379 extern "C" {
380 #endif
381 static inline int
vasprintf(char ** const sptr,const char * const fmt,va_list argv)382 vasprintf( char ** const sptr, const char *const fmt, va_list argv )
383 {
384     int wanted = vsnprintf( *sptr = NULL, 0, fmt, argv );
385     if (wanted<0)
386         return -1;
387     *sptr = (char *) malloc(1 + wanted);
388     if (!*sptr)
389         return -1;
390     int rc = vsnprintf(*sptr, 1+wanted, fmt, argv );
391     return rc;
392 }
393 
394 static inline int
asprintf(char ** const sptr,const char * const fmt,...)395 asprintf( char ** const sptr, const char * const fmt, ... )
396 {
397     int retval;
398     va_list argv;
399     va_start(argv, fmt);
400     retval = vasprintf(sptr, fmt, argv);
401     va_end(argv);
402     return retval;
403 }
404 #ifdef __cplusplus
405 }
406 #endif
407 #endif  /* HAVE_ASPRINTF *//*}}}*/
408 
409 #if defined(HAVE_MINGW) && !defined(HAVE_REALPATH)/*{{{*/
410 #include <io.h>
411 #include <stdlib.h>
412 #include <errno.h>
413 /* realpath() function copied from
414  * http://sourceforge.net/p/mingw/patches/256/?page=0
415  * Its copyright notice is:
416  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
417  *
418  * This is free software.  You may redistribute and/or modify it as you
419  * see fit, without restriction of copyright. */
420 
421 static inline char __cdecl
realpath(const char * __restrict__ name,char * __restrict__ resolved)422 *realpath( const char *__restrict__ name, char *__restrict__ resolved )
423 {
424   char *retname = NULL;
425 
426   if( name == NULL )
427     errno = EINVAL;
428   else if( access( name, 4 ) == 0 )
429   {
430     if( (retname = resolved) == NULL )
431     {
432       retname = (char *) malloc( _MAX_PATH );
433     }
434     if( retname == NULL )
435       errno = ENOMEM;
436     else if( (retname = _fullpath( retname, name, _MAX_PATH )) == NULL )
437       errno = ENAMETOOLONG;
438   }
439   return retname;
440 }
441 #endif/*}}}*/
442 
443 #if defined(HAVE_SYSCONF)/*{{{*/
444 #include <unistd.h>
445 #endif/*}}}*/
446 
447 #if defined(_WIN32) || defined(_WIN64)  /* mingw lacks pagesize() *//*{{{*/
448 #include <windows.h>
449 #endif
pagesize()450 static inline long pagesize ()
451 {
452 #if defined(_WIN32) || defined(_WIN64)
453   /* cf http://en.wikipedia.org/wiki/Page_%28computer_memory%29 */
454   SYSTEM_INFO si;
455   GetSystemInfo(&si);
456   return si.dwPageSize;
457 #elif defined(HAVE_SYSCONF)
458   return sysconf (_SC_PAGESIZE);
459 #else
460   #error "Cannot determine page size"
461 #endif
462 }/*}}}*/
463 
464 #ifdef HAVE_MINGW       /* mingw lacks sleep() (!?!!?) *//*{{{*/
465 /* oh dear... */
466 #include <windows.h>
467 #define sleep(seconds) Sleep((seconds)*1000)
468 #endif /* HAVE_MINGW *//*}}}*/
469 
470 #endif /* ifndef CADO_PORTABILITY_H_ */
471