1 /*
2  * Copyright (c) The Piglit project 2007
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
18  * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21  * USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #pragma once
25 #ifndef PIGLIT_UTIL_H
26 #define PIGLIT_UTIL_H
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 #include "config.h"
33 
34 #if defined(_WIN32)
35 
36 #include <windows.h>
37 
38 /* Another two macros provided by windows.h which conflict with piglit */
39 #undef near
40 #undef far
41 #define strdup _strdup
42 
43 #endif
44 
45 #include <assert.h>
46 #include <stdbool.h>
47 #include <stdint.h>
48 #include <string.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <stdarg.h>
52 #include <math.h>
53 #include <float.h>
54 
55 #if defined(__APPLE__) || defined(__MINGW32__)
56 #  include "libgen.h" // for basename
57 #elif defined(_MSC_VER)
58 
59 static inline char *
60 basename(const char *path)
61 {
62 	static char path_buffer[_MAX_PATH];
63 	char drive[_MAX_DRIVE];
64 	char dir[_MAX_DIR];
65 	char fname[_MAX_FNAME];
66 	char ext[_MAX_EXT];
67 
68 	_splitpath(path, drive, dir, fname, ext);
69 	_makepath(path_buffer, NULL , NULL, fname, ext);
70 	return path_buffer;
71 }
72 
73 #endif
74 
75 #include "piglit-log.h"
76 
77 #ifndef __has_attribute
78 #define __has_attribute(x) 0
79 #endif
80 
81 #if defined(__GNUC__) || __has_attribute(noreturn)
82 #define NORETURN __attribute__((noreturn))
83 #elif defined(_MSC_VER)
84 #define NORETURN __declspec(noreturn)
85 #else
86 #define NORETURN
87 #endif
88 
89 #ifndef HAVE_ASPRINTF
90 int asprintf(char **strp, const char *fmt, ...) PRINTFLIKE(2, 3);
91 #endif /* HAVE_ASPRINTF */
92 
93 #ifndef HAVE_FFS
94 #ifdef __MINGW32__
95 #define ffs __builtin_ffs
96 #else /* !__MINGW32__ */
97 
98 /**
99  * Find the first bit set in i and return the index set of that bit.
100  */
101 static inline int
ffs(int i)102 ffs(int i)
103 {
104 	int bit;
105 
106 	if (i == 0) {
107 		return 0;
108 	}
109 
110 	for (bit = 1; !(i & 1); bit++) {
111 		i = i >> 1;
112 	}
113 
114 	return bit;
115 }
116 
117 #endif /* !__MINGW32__ */
118 #endif /* !HAVE_FFS*/
119 
120 #ifndef HAVE_HTOBE32
121 static inline uint32_t
htobe32(uint32_t host_32bits)122 htobe32(uint32_t host_32bits)
123 {
124 #ifdef __BIG_ENDIAN__
125 	return host_32bits;
126 #else
127 	return ((host_32bits >> 24) & 0x000000FF) |
128 	       ((host_32bits >> 16) & 0x0000FF00) |
129 	       ((host_32bits >>  8) & 0x00FF0000) |
130 	       (host_32bits         & 0xFF000000);
131 #endif
132 }
133 #endif /* HAVE_ASPRINTF */
134 
135 #ifdef _WIN32
136 #  define PIGLIT_PATH_SEP '\\'
137 #else
138 #  define PIGLIT_PATH_SEP '/'
139 #endif
140 
141 enum piglit_result {
142 	PIGLIT_PASS,
143 	PIGLIT_FAIL,
144 	PIGLIT_SKIP,
145 	PIGLIT_WARN
146 };
147 
148 /**
149  * An individual subtest that makes up part of a test group.
150  */
151 struct piglit_subtest {
152 	/** Name of the subtest as it will appear in the log. */
153 	const char *name;
154 
155 	/** Command line name used to select this test. */
156 	const char *option;
157 
158 	/** Function that implements the test. */
159 	enum piglit_result (*subtest_func)(void *data);
160 
161 	/** Passed as the data parameter to subtest_func.*/
162 	void *data;
163 };
164 
165 /**
166  * Detect the end of an array of piglit_subtest structures
167  *
168  * The array of subtests is terminated by structure with a \c NULL \c
169  * name pointer.
170  */
171 #define PIGLIT_SUBTEST_END(s) ((s)->name == NULL)
172 
173 const struct piglit_subtest*
174 piglit_find_subtest(const struct piglit_subtest *subtests, const char *name);
175 
176 enum piglit_result
177 piglit_run_selected_subtests(const struct piglit_subtest *all_subtests,
178 			     const char **selected_subtests,
179 			     size_t num_selected_subtests,
180 			     enum piglit_result previous_result);
181 
182 void
183 piglit_register_subtests(const char *names[]);
184 
185 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
186 
187 #define CLAMP( X, MIN, MAX )  ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
188 #define MIN2(a, b) ((a) > (b) ? (b) : (a))
189 #define MAX2(a, b) ((a) > (b) ? (a) : (b))
190 #define MIN3(a, b, c) MIN2(MIN2((a), (b)), (c))
191 #define MAX3(a, b, c) MAX2(MAX2((a), (b)), (c))
192 #define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1))
193 
194 /**
195  * Utility macro that checks for a given opengl error, and report a
196  * subtest result.
197  */
198 #define PIGLIT_SUBTEST_ERROR(error, global, ...) \
199 do { \
200 	bool local = piglit_check_gl_error((error)); \
201 	global = global && local; \
202 	piglit_report_subtest_result(local ? PIGLIT_PASS : PIGLIT_FAIL, \
203 				     __VA_ARGS__);			\
204 } while (0)
205 
206 /**
207  * Utility macro that checks for a given condition, and report a
208  * subtest result.
209  */
210 #define PIGLIT_SUBTEST_CONDITION(condition, global, ...) \
211 do { \
212 	bool cond = (condition); \
213 	global = global && cond; \
214 	piglit_report_subtest_result(cond ? PIGLIT_PASS : PIGLIT_FAIL, \
215 				     __VA_ARGS__);		       \
216 } while (0)
217 
218 static inline unsigned
log2u(unsigned v)219 log2u(unsigned v)
220 {
221 #ifdef __GCC__
222 	return v == 0 ? 0 : 31 - __builtin_clz(v);
223 #else
224 	unsigned res = 0;
225 
226 	while (v >>= 1)
227 		res++;
228 
229 	return res;
230 #endif
231 }
232 
233 /**
234  * Returns the smallest power-of-two integer greater than or equal to v
235  */
236 static inline unsigned
next_power_of_two(unsigned v)237 next_power_of_two(unsigned v)
238 {
239 	/* Special case zero because 1U << 32 is undefined. */
240 	return v == 0 ? 1 : 1U << (log2u(v - 1) + 1);
241 }
242 
243 
244 /**
245  * Return true if and only if two string are equal according to strcmp().
246  */
247 static inline bool
streq(const char * a,const char * b)248 streq(const char *a, const char *b)
249 {
250 	return strcmp(a, b) == 0;
251 }
252 
253 /**
254  * Wrapper for strtod() which also handles +/-inf with MSVC.
255  * Note: we only check for "inf" and not "INF".
256  */
257 static inline double
strtod_inf(const char * nptr,char ** endptr)258 strtod_inf(const char *nptr, char **endptr)
259 {
260 	return strtod(nptr, endptr);
261 }
262 
263 /**
264  * Wrapper for strtod_inf() which allows using an exact hex bit
265  * pattern to generate a float value.
266  */
267 static inline float
strtof_hex(const char * nptr,char ** endptr)268 strtof_hex(const char *nptr, char **endptr)
269 {
270 	/* skip spaces and tabs */
271 	while (*nptr == ' ' || *nptr == '\t')
272 		nptr++;
273 
274 	if (strncmp(nptr, "0x", 2) == 0) {
275 		union {
276 			uint32_t u;
277 			float f;
278 		} x;
279 
280 		x.u = strtoul(nptr, endptr, 16);
281 		return x.f;
282 	} else {
283 		return strtod_inf(nptr, endptr);
284 	}
285 }
286 
287 /**
288  * Wrapper for strtod_inf() which allows using an exact hex bit
289  * pattern to generate a double value.
290  */
291 static inline double
strtod_hex(const char * nptr,char ** endptr)292 strtod_hex(const char *nptr, char **endptr)
293 {
294 	/* skip spaces and tabs */
295 	while (*nptr == ' ' || *nptr == '\t')
296 		nptr++;
297 
298 	if (strncmp(nptr, "0x", 2) == 0) {
299 		union {
300 			uint64_t u64;
301 			double d;
302 		} x;
303 
304 		x.u64 = strtoull(nptr, endptr, 16);
305 		return x.d;
306 	} else {
307 		return strtod_inf(nptr, endptr);
308 	}
309 }
310 
311 /**
312  * Wrapper for strtol() which allows using an exact hex bit pattern to
313  * generate a signed int value.
314  */
315 static inline int
strtol_hex(const char * nptr,char ** endptr)316 strtol_hex(const char *nptr, char **endptr)
317 {
318 	/* skip spaces and tabs */
319 	while (*nptr == ' ' || *nptr == '\t')
320 		nptr++;
321 
322 	if (strncmp(nptr, "0x", 2) == 0) {
323 		union {
324 			uint32_t u;
325 			int32_t i;
326 		} x;
327 
328 		x.u = strtoul(nptr, endptr, 16);
329 		return x.i;
330 	} else {
331 		return strtol(nptr, endptr, 0);
332 	}
333 }
334 
335 #ifndef HAVE_STRCHRNUL
336 static inline char *
strchrnul(const char * s,int c)337 strchrnul(const char *s, int c)
338 {
339        const char *t = strchr(s, c);
340 
341        return (t == NULL) ? ((char *) s + strlen(s)) : (char *) t;
342 }
343 #endif
344 
345 
346 #ifndef HAVE_STRNDUP
347 static inline char *
strndup(const char * s,size_t n)348 strndup(const char *s, size_t n)
349 {
350 	const size_t len = strlen(s);
351 	const size_t size_to_copy = MIN2(n, len);
352 
353 	char *const copy = (char *const) malloc(size_to_copy + 1);
354 	if (copy != NULL) {
355 		memcpy(copy, s, size_to_copy);
356 		copy[size_to_copy] = '\0';
357 	}
358 
359 	return copy;
360 }
361 #endif
362 
363 #ifdef _MSC_VER
364 static inline int
vasprintf(char ** strp,const char * fmt,va_list ap)365 vasprintf(char **strp, const char *fmt, va_list ap)
366 {
367 	int len = _vscprintf(fmt, ap);
368 	if (len < 0)
369 		return -1;
370 
371 	char *str = (char *)malloc(len + 1);
372 	if (!str)
373 		return -1;
374 
375 	int r = vsprintf_s(str, len + 1, fmt, ap);
376 	if (r < 0) {
377 		free(str);
378 		return -1;
379 	}
380 
381 	*strp = str;
382 	return r;
383 }
384 #endif
385 
386 /**
387  * Determine if an extension is listed in an extension string
388  *
389  * \param haystack   List of all extensions to be searched
390  * \param needle     Extension whose presens is to be detected
391  *
392  * \precondition \c haystack is not null
393  *
394  * \sa piglit_is_extension_supported, piglit_is_glx_extension_supported
395  */
396 bool piglit_is_extension_in_string(const char *haystack, const char *needle);
397 
398 /**
399  * Determine if an extension is listed in an extension string array
400  *
401  * \param haystack   Array of all extensions to be searched
402  * \param needle     Extension whose presens is to be detected
403  *
404  * \precondition \c haystack is not null
405  *
406  * \sa piglit_is_extension_supported, piglit_is_glx_extension_supported
407  */
408 bool piglit_is_extension_in_array(const char **haystack, const char *needle);
409 
410 int piglit_find_line(const char *program, int position);
411 void piglit_merge_result(enum piglit_result *all, enum piglit_result subtest);
412 const char * piglit_result_to_string(enum piglit_result result);
413 NORETURN void piglit_report_result(enum piglit_result result);
414 void piglit_set_timeout(double seconds, enum piglit_result timeout_result);
415 void piglit_report_subtest_result(enum piglit_result result,
416 				  const char *format, ...) PRINTFLIKE(2, 3);
417 
418 void piglit_general_init(void);
419 
420 extern void piglit_set_rlimit(unsigned long lim);
421 
422 char *piglit_load_text_file(const char *file_name, unsigned *size);
423 
424 /**
425  * \brief Read environment variable PIGLIT_SOURCE_DIR.
426  *
427  * If environment is not defined, then report failure. The intention is
428  * that tests should use this to construct the path to any needed data files.
429  */
430 const char*
431 piglit_source_dir(void);
432 
433 /**
434  * \brief Join paths together with the system path separator.
435  *
436  * On Unix, the path separator is '/'. On Windows, '\\'.
437  *
438  * The variable argument consists of \a n null-terminated strings.  The
439  * resultant path is written to \a buf.  No more than \a buf_size bytes are
440  * written to \a buf. The last byte written is always the null character.
441  * Returned is the number of bytes written, including the terminating null.
442  */
443 size_t
444 piglit_join_paths(char buf[], size_t buf_size, int n, ...);
445 
446 /**
447  * \brief Reads an environment variable and interprets its value as a boolean.
448  *
449  * Recognizes 0/false/no and 1/true/yes.  Other values result in the
450  * \a default_value.
451  */
452 bool
453 piglit_env_var_as_boolean(const char *var_name, bool default_value);
454 
455 /**
456  * \brief Whether piglit_time_get* return monotonically increasing time.
457  *
458  * Can be used to determine how accurate/reliable the time returned by the
459  * function(s) is.
460  */
461 bool
462 piglit_time_is_monotonic();
463 
464 /**
465  * \brief Get the time in nanoseconds
466  *
467  * This time can be used for relative time measurements.
468  *
469  * A negative return value indicates an error.
470  *
471  * \sa piglit_time_is_monotonic
472  */
473 int64_t
474 piglit_time_get_nano(void);
475 
476 /**
477  * \brief Try to delay for a given duration
478  *
479  * \param time_ns	The requested duration to wait for
480  *
481  * Returns the time elapsed which may be cut short or overrun the requested
482  * duration, e.g. due to signal handling or scheduling.
483  *
484  * \sa on Linux nanosleep is used and restarted on SIGINT
485  * \sa usleep() is use on other OSs
486  * \sa the returned duration is timed using piglit_time_get_nano()
487  */
488 int64_t
489 piglit_delay_ns(int64_t time_ns);
490 
491 const char**
492 piglit_split_string_to_array(const char *string, const char *separators);
493 
494 bool
495 piglit_strip_arg(int *argc, char *argv[], const char *arg);
496 
497 void
498 piglit_parse_subtest_args(int *argc, char *argv[],
499 			  const struct piglit_subtest *subtests,
500 			  const char ***out_selected_subtests,
501 			  size_t *out_num_selected_subtests);
502 
503 /**
504  * \brief Return the thread id.
505  *
506  * On Linux, this functions wraps the gettid() syscall.
507  * On unsupported systems, this returns 0.
508  */
509 uint64_t
510 piglit_gettid(void);
511 
512 size_t
513 piglit_get_page_size(void);
514 
515 void *
516 piglit_alloc_aligned(size_t alignment, size_t size);
517 
518 void
519 piglit_free_aligned(void *p);
520 
521 union uif {
522 	float f;
523 	unsigned int ui;
524 };
525 
526 static inline unsigned int
fui(float f)527 fui(float f)
528 {
529 	union uif bits;
530 	bits.f = f;
531 	return bits.ui;
532 }
533 
534 static inline float
uif(unsigned int ui)535 uif(unsigned int ui)
536 {
537 	union uif bits;
538 	bits.ui = ui;
539 	return bits.f;
540 }
541 
542 #ifdef __cplusplus
543 } /* end extern "C" */
544 #endif
545 
546 #endif /* PIGLIT_UTIL_H */
547