aboutsummaryrefslogblamecommitdiffstats
path: root/multimespec.c
blob: ee0e1f304321f6a0c869234bb60de789b650aa7e (plain) (tree)
1
2
3
4
5
6
7
                                                         
                   
            


   
                                                                                                 

























                                                                   
                                                                                 
                              
 
                                                                                  
                              

























                                              









                             

                       



                                                  

                       



                                                  

                        



                                                  

                        



                                                  

                       



                                                  

                       



                                                  

                        



                                                  

                        



                                                  

                       



                                                   

                       



                                                   

                        



                                                   

                        



                                                   

                       



                                                   

                       



                                                   

                        



                                                   

                        



                                                   

                       



                                                    

                       



                                                    

                        



                                                    

                        



                                                    

                               



                                                  

                               



                                                  

                             



                                                                          

                             



                                                                           

                             




                                                   

                                       




                                                           

                               







                                                   
/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifndef TEST


int
libsimple_multimespec(struct timespec *prod, const struct timespec *multiplicand, int multiplier)
{
	time_t s = multiplicand->tv_sec;
	long long int ns = (long long int)(multiplicand->tv_nsec);
	long long int xs;
	int neg = (s < 0) ^ (multiplier < 0);

	if (multiplier == 0 || multiplier == 1) {
		prod->tv_sec = multiplier * multiplicand->tv_sec;
		prod->tv_nsec = multiplier * multiplicand->tv_nsec;
		return 0;
	}

	if (s < 0) {
		if (TIME_MIN != -TIME_MAX && s == TIME_MIN)
			goto overflow;
		s = -s;
		if (ns)
			ns = 1000000000L - ns;
	}
	if (multiplier < 0)
		multiplier = -multiplier;

	ns *= multiplier;
	xs = ns / 1000000000L;
	ns %= 1000000000L;

	if (LIBSIMPLE_SMUL_OVERFLOW_AP_BP(s, multiplier, &s, TIME_MIN, TIME_MAX))
		goto overflow;

	if (LIBSIMPLE_SADD_OVERFLOW_NONNEG(s, (time_t)xs, &s, TIME_MIN, TIME_MAX))
		goto overflow;

	if (neg) {
		s = -s;
		if (ns) {
			if (s == TIME_MIN)
				goto overflow;
			ns = 1000000000L - ns;
			s -= 1;
		}
	}

	prod->tv_sec = s;
	prod->tv_nsec = ns;
	return 0;

overflow:
	if (neg) {
		prod->tv_sec = TIME_MIN;
		prod->tv_nsec = 0;
	} else {
		prod->tv_sec = TIME_MAX;
		prod->tv_nsec = 999999999L;
	}
	errno = ERANGE;
	return -1;
}


#else
#include "test.h"

int
main(void)
{
	struct timespec r, a;

	a.tv_sec  = 0;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, 0));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 10;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, 0));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 0;
	a.tv_nsec = 10L;
	assert(!libsimple_multimespec(&r, &a, 0));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 10;
	a.tv_nsec = 10L;
	assert(!libsimple_multimespec(&r, &a, 0));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 0;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, 1));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 10;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, 1));
	assert(r.tv_sec  == 10);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 0;
	a.tv_nsec = 10L;
	assert(!libsimple_multimespec(&r, &a, 1));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 10L);

	a.tv_sec  = 10;
	a.tv_nsec = 10L;
	assert(!libsimple_multimespec(&r, &a, 1));
	assert(r.tv_sec  == 10);
	assert(r.tv_nsec == 10L);

	a.tv_sec  = 0;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, 10));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 10;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, 10));
	assert(r.tv_sec  == 100);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 0;
	a.tv_nsec = 10L;
	assert(!libsimple_multimespec(&r, &a, 10));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 100L);

	a.tv_sec  = 10;
	a.tv_nsec = 10L;
	assert(!libsimple_multimespec(&r, &a, 10));
	assert(r.tv_sec  == 100);
	assert(r.tv_nsec == 100L);

	a.tv_sec  = 0;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, -1));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 10;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, -1));
	assert(r.tv_sec  == -10);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 0;
	a.tv_nsec = 10L;
	assert(!libsimple_multimespec(&r, &a, -1));
	assert(r.tv_sec  == -1);
	assert(r.tv_nsec == 1000000000L - 10L);

	a.tv_sec  = 10;
	a.tv_nsec = 10L;
	assert(!libsimple_multimespec(&r, &a, -1));
	assert(r.tv_sec  == -11);
	assert(r.tv_nsec == 1000000000L - 10L);

	a.tv_sec  = 0;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, -10));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 10;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, -10));
	assert(r.tv_sec  == -100);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = 0;
	a.tv_nsec = 10L;
	assert(!libsimple_multimespec(&r, &a, -10));
	assert(r.tv_sec  == -1);
	assert(r.tv_nsec == 1000000000L - 100L);

	a.tv_sec  = 10;
	a.tv_nsec = 10L;
	assert(!libsimple_multimespec(&r, &a, -10));
	assert(r.tv_sec  == -101);
	assert(r.tv_nsec == 1000000000L - 100L);

	a.tv_sec  = TIME_MAX;
	a.tv_nsec = 999999999L;
	assert(!libsimple_multimespec(&r, &a, 0));
	assert(r.tv_sec  == 0);
	assert(r.tv_nsec == 0);

	a.tv_sec  = TIME_MAX;
	a.tv_nsec = 999999999L;
	assert(!libsimple_multimespec(&r, &a, 1));
	assert(r.tv_sec  == TIME_MAX);
	assert(r.tv_nsec == 999999999L);

	a.tv_sec  = TIME_MAX;
	a.tv_nsec = 0L;
	assert(libsimple_multimespec(&r, &a, 2) == -1 && errno == ERANGE);
	assert(r.tv_sec  == TIME_MAX);
	assert(r.tv_nsec == 999999999L);

	a.tv_sec  = TIME_MAX;
	a.tv_nsec = 0L;
	assert(libsimple_multimespec(&r, &a, -2) == -1 && errno == ERANGE);
	assert(r.tv_sec  == TIME_MIN);
	assert(r.tv_nsec == 0L);

	a.tv_sec  = TIME_MAX;
	a.tv_nsec = 0L;
	assert(!libsimple_multimespec(&r, &a, -1));
	assert(r.tv_sec  == -TIME_MAX);
	assert(r.tv_nsec == 0L);

	if (-TIME_MAX > TIME_MIN) {
		a.tv_sec  = TIME_MAX;
		a.tv_nsec = 999999999L;
		assert(!libsimple_multimespec(&r, &a, -1));
		assert(r.tv_sec  == -TIME_MAX - (time_t)1);
		assert(r.tv_nsec == 1L);
	}

	a.tv_sec  = 10;
	a.tv_nsec = 100000001L;
	assert(!libsimple_multimespec(&r, &a, 10));
	assert(r.tv_sec  == 101);
	assert(r.tv_nsec == 10L);

	return 0;
}

#endif