xref: /dflybsd-src/usr.bin/calendar/utils.c (revision d19ef5a274debcb71f2e8cd8dce8b954dc73944b)
1*d19ef5a2SAaron LI /*-
2*d19ef5a2SAaron LI  * SPDX-License-Identifier: BSD-3-Clause
3*d19ef5a2SAaron LI  *
4*d19ef5a2SAaron LI  * Copyright (c) 2019-2020 The DragonFly Project.  All rights reserved.
5*d19ef5a2SAaron LI  *
6*d19ef5a2SAaron LI  * This code is derived from software contributed to The DragonFly Project
7*d19ef5a2SAaron LI  * by Aaron LI <aly@aaronly.me>
8*d19ef5a2SAaron LI  *
9*d19ef5a2SAaron LI  * Redistribution and use in source and binary forms, with or without
10*d19ef5a2SAaron LI  * modification, are permitted provided that the following conditions
11*d19ef5a2SAaron LI  * are met:
12*d19ef5a2SAaron LI  *
13*d19ef5a2SAaron LI  * 1. Redistributions of source code must retain the above copyright
14*d19ef5a2SAaron LI  *    notice, this list of conditions and the following disclaimer.
15*d19ef5a2SAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
16*d19ef5a2SAaron LI  *    notice, this list of conditions and the following disclaimer in
17*d19ef5a2SAaron LI  *    the documentation and/or other materials provided with the
18*d19ef5a2SAaron LI  *    distribution.
19*d19ef5a2SAaron LI  * 3. Neither the name of The DragonFly Project nor the names of its
20*d19ef5a2SAaron LI  *    contributors may be used to endorse or promote products derived
21*d19ef5a2SAaron LI  *    from this software without specific, prior written permission.
22*d19ef5a2SAaron LI  *
23*d19ef5a2SAaron LI  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*d19ef5a2SAaron LI  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25*d19ef5a2SAaron LI  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26*d19ef5a2SAaron LI  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27*d19ef5a2SAaron LI  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28*d19ef5a2SAaron LI  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29*d19ef5a2SAaron LI  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30*d19ef5a2SAaron LI  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31*d19ef5a2SAaron LI  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32*d19ef5a2SAaron LI  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33*d19ef5a2SAaron LI  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34*d19ef5a2SAaron LI  * SUCH DAMAGE.
35*d19ef5a2SAaron LI  *
36*d19ef5a2SAaron LI  * Reference:
37*d19ef5a2SAaron LI  * Calendrical Calculations, The Ultimate Edition (4th Edition)
38*d19ef5a2SAaron LI  * by Edward M. Reingold and Nachum Dershowitz
39*d19ef5a2SAaron LI  * 2018, Cambridge University Press
40*d19ef5a2SAaron LI  */
41*d19ef5a2SAaron LI 
42*d19ef5a2SAaron LI #include <err.h>
43*d19ef5a2SAaron LI #include <math.h>
44*d19ef5a2SAaron LI #include <stdbool.h>
45*d19ef5a2SAaron LI #include <stddef.h>
46*d19ef5a2SAaron LI #include <stdio.h>
47*d19ef5a2SAaron LI #include <stdlib.h>
48*d19ef5a2SAaron LI #include <string.h>
49*d19ef5a2SAaron LI 
50*d19ef5a2SAaron LI #include "utils.h"
51*d19ef5a2SAaron LI 
52*d19ef5a2SAaron LI 
53*d19ef5a2SAaron LI /*
54*d19ef5a2SAaron LI  * Calculate the polynomial: c[0] + c[1] * x + ... + c[n-1] * x^(n-1)
55*d19ef5a2SAaron LI  */
56*d19ef5a2SAaron LI double
poly(double x,const double * coefs,size_t n)57*d19ef5a2SAaron LI poly(double x, const double *coefs, size_t n)
58*d19ef5a2SAaron LI {
59*d19ef5a2SAaron LI 	double p = 0.0;
60*d19ef5a2SAaron LI 	double t = 1.0;
61*d19ef5a2SAaron LI 	for (size_t i = 0; i < n; i++) {
62*d19ef5a2SAaron LI 		p += t * coefs[i];
63*d19ef5a2SAaron LI 		t *= x;
64*d19ef5a2SAaron LI 	}
65*d19ef5a2SAaron LI 	return p;
66*d19ef5a2SAaron LI }
67*d19ef5a2SAaron LI 
68*d19ef5a2SAaron LI /*
69*d19ef5a2SAaron LI  * Use bisection search to find the inverse of the given angular function
70*d19ef5a2SAaron LI  * $f(x) at value $y (degrees) within time interval [$a, $b].
71*d19ef5a2SAaron LI  * Ref: Sec.(1.8), Eq.(1.36)
72*d19ef5a2SAaron LI  */
73*d19ef5a2SAaron LI double
invert_angular(double (* f)(double),double y,double a,double b)74*d19ef5a2SAaron LI invert_angular(double (*f)(double), double y, double a, double b)
75*d19ef5a2SAaron LI {
76*d19ef5a2SAaron LI 	static const double eps = 1e-6;
77*d19ef5a2SAaron LI 	double x;
78*d19ef5a2SAaron LI 
79*d19ef5a2SAaron LI 	do {
80*d19ef5a2SAaron LI 		x = (a + b) / 2.0;
81*d19ef5a2SAaron LI 		if (mod_f(f(x) - y, 360) < 180.0)
82*d19ef5a2SAaron LI 			b = x;
83*d19ef5a2SAaron LI 		else
84*d19ef5a2SAaron LI 			a = x;
85*d19ef5a2SAaron LI 	} while (fabs(a-b) >= eps);
86*d19ef5a2SAaron LI 
87*d19ef5a2SAaron LI 	return x;
88*d19ef5a2SAaron LI }
89*d19ef5a2SAaron LI 
90*d19ef5a2SAaron LI 
91*d19ef5a2SAaron LI /*
92*d19ef5a2SAaron LI  * Like malloc(3) but exit if allocation fails.
93*d19ef5a2SAaron LI  */
94*d19ef5a2SAaron LI void *
xmalloc(size_t size)95*d19ef5a2SAaron LI xmalloc(size_t size)
96*d19ef5a2SAaron LI {
97*d19ef5a2SAaron LI 	void *ptr = malloc(size);
98*d19ef5a2SAaron LI 	if (ptr == NULL)
99*d19ef5a2SAaron LI 		errx(1, "mcalloc(%zu): out of memory", size);
100*d19ef5a2SAaron LI 	return ptr;
101*d19ef5a2SAaron LI }
102*d19ef5a2SAaron LI 
103*d19ef5a2SAaron LI /*
104*d19ef5a2SAaron LI  * Like calloc(3) but exit if allocation fails.
105*d19ef5a2SAaron LI  */
106*d19ef5a2SAaron LI void *
xcalloc(size_t number,size_t size)107*d19ef5a2SAaron LI xcalloc(size_t number, size_t size)
108*d19ef5a2SAaron LI {
109*d19ef5a2SAaron LI 	void *ptr = calloc(number, size);
110*d19ef5a2SAaron LI 	if (ptr == NULL)
111*d19ef5a2SAaron LI 		errx(1, "xcalloc(%zu, %zu): out of memory", number, size);
112*d19ef5a2SAaron LI 	return ptr;
113*d19ef5a2SAaron LI }
114*d19ef5a2SAaron LI 
115*d19ef5a2SAaron LI /*
116*d19ef5a2SAaron LI  * Like realloc(3) but exit if allocation fails.
117*d19ef5a2SAaron LI  */
118*d19ef5a2SAaron LI void *
xrealloc(void * ptr,size_t size)119*d19ef5a2SAaron LI xrealloc(void *ptr, size_t size)
120*d19ef5a2SAaron LI {
121*d19ef5a2SAaron LI 	ptr = realloc(ptr, size);
122*d19ef5a2SAaron LI 	if (ptr == NULL)
123*d19ef5a2SAaron LI 		errx(1, "xrealloc: out of memory (size: %zu)", size);
124*d19ef5a2SAaron LI 	return ptr;
125*d19ef5a2SAaron LI }
126*d19ef5a2SAaron LI 
127*d19ef5a2SAaron LI /*
128*d19ef5a2SAaron LI  * Like strdup(3) but exit if fail.
129*d19ef5a2SAaron LI  */
130*d19ef5a2SAaron LI char *
xstrdup(const char * str)131*d19ef5a2SAaron LI xstrdup(const char *str)
132*d19ef5a2SAaron LI {
133*d19ef5a2SAaron LI 	char *p = strdup(str);
134*d19ef5a2SAaron LI 	if (p == NULL)
135*d19ef5a2SAaron LI 		errx(1, "xstrdup: out of memory (length: %zu)", strlen(str));
136*d19ef5a2SAaron LI 	return p;
137*d19ef5a2SAaron LI }
138*d19ef5a2SAaron LI 
139*d19ef5a2SAaron LI 
140*d19ef5a2SAaron LI /*
141*d19ef5a2SAaron LI  * Linked list implementation
142*d19ef5a2SAaron LI  */
143*d19ef5a2SAaron LI 
144*d19ef5a2SAaron LI struct node {
145*d19ef5a2SAaron LI 	char		*name;
146*d19ef5a2SAaron LI 	void		*data;
147*d19ef5a2SAaron LI 	struct node	*next;
148*d19ef5a2SAaron LI };
149*d19ef5a2SAaron LI 
150*d19ef5a2SAaron LI /*
151*d19ef5a2SAaron LI  * Create a new list node with the given $name and $data.
152*d19ef5a2SAaron LI  */
153*d19ef5a2SAaron LI struct node *
list_newnode(char * name,void * data)154*d19ef5a2SAaron LI list_newnode(char *name, void *data)
155*d19ef5a2SAaron LI {
156*d19ef5a2SAaron LI 	struct node *newp;
157*d19ef5a2SAaron LI 
158*d19ef5a2SAaron LI 	newp = xcalloc(1, sizeof(*newp));
159*d19ef5a2SAaron LI 	newp->name = name;
160*d19ef5a2SAaron LI 	newp->data = data;
161*d19ef5a2SAaron LI 
162*d19ef5a2SAaron LI 	return newp;
163*d19ef5a2SAaron LI }
164*d19ef5a2SAaron LI 
165*d19ef5a2SAaron LI /*
166*d19ef5a2SAaron LI  * Add $newp to the front of list $listp.
167*d19ef5a2SAaron LI  */
168*d19ef5a2SAaron LI struct node *
list_addfront(struct node * listp,struct node * newp)169*d19ef5a2SAaron LI list_addfront(struct node *listp, struct node *newp)
170*d19ef5a2SAaron LI {
171*d19ef5a2SAaron LI 	newp->next = listp;
172*d19ef5a2SAaron LI 	return newp;
173*d19ef5a2SAaron LI }
174*d19ef5a2SAaron LI 
175*d19ef5a2SAaron LI /*
176*d19ef5a2SAaron LI  * Lookup the given $name in the list $listp.
177*d19ef5a2SAaron LI  * The $cmp function compares two names and return 0 if they equal.
178*d19ef5a2SAaron LI  * Return the associated data with the found node, otherwise NULL.
179*d19ef5a2SAaron LI  */
180*d19ef5a2SAaron LI bool
list_lookup(struct node * listp,const char * name,int (* cmp)(const char *,const char *),void ** data_out)181*d19ef5a2SAaron LI list_lookup(struct node *listp, const char *name,
182*d19ef5a2SAaron LI 	    int (*cmp)(const char *, const char *), void **data_out)
183*d19ef5a2SAaron LI {
184*d19ef5a2SAaron LI 	for ( ; listp; listp = listp->next) {
185*d19ef5a2SAaron LI 		if ((*cmp)(name, listp->name) == 0) {
186*d19ef5a2SAaron LI 			if (data_out)
187*d19ef5a2SAaron LI 				*data_out = listp->data;
188*d19ef5a2SAaron LI 			return true;
189*d19ef5a2SAaron LI 		}
190*d19ef5a2SAaron LI 	}
191*d19ef5a2SAaron LI 
192*d19ef5a2SAaron LI 	return false;
193*d19ef5a2SAaron LI }
194*d19ef5a2SAaron LI 
195*d19ef5a2SAaron LI /*
196*d19ef5a2SAaron LI  * Free all nodes of list $listp.
197*d19ef5a2SAaron LI  */
198*d19ef5a2SAaron LI void
list_freeall(struct node * listp,void (* free_name)(void *),void (* free_data)(void *))199*d19ef5a2SAaron LI list_freeall(struct node *listp,
200*d19ef5a2SAaron LI 	     void (*free_name)(void *),
201*d19ef5a2SAaron LI 	     void (*free_data)(void *))
202*d19ef5a2SAaron LI {
203*d19ef5a2SAaron LI 	struct node *cur;
204*d19ef5a2SAaron LI 
205*d19ef5a2SAaron LI 	while (listp) {
206*d19ef5a2SAaron LI 		cur = listp;
207*d19ef5a2SAaron LI 		listp = listp->next;
208*d19ef5a2SAaron LI 		if (free_name)
209*d19ef5a2SAaron LI 			(*free_name)(cur->name);
210*d19ef5a2SAaron LI 		if (free_data)
211*d19ef5a2SAaron LI 			(*free_data)(cur->data);
212*d19ef5a2SAaron LI 		free(cur);
213*d19ef5a2SAaron LI 	}
214*d19ef5a2SAaron LI }
215