libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
Loading...
Searching...
No Matches
helpers.h
Go to the documentation of this file.
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license in the file COPYING
10 * or http://www.opensource.org/licenses/CDDL-1.0.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file COPYING.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2023 Saso Kiselkov. All rights reserved.
24 */
30#ifndef _ACF_UTILS_HELPERS_H_
31#define _ACF_UTILS_HELPERS_H_
32
33#include <ctype.h>
34#include <stdarg.h>
35#include <stdio.h>
36#include <string.h>
37#include <sys/types.h>
38#include <math.h>
39#if APL || LIN
40#include <sys/stat.h>
41#include <dirent.h> /* to bring in DIR, opendir, readdir & friends */
42#include <unistd.h>
43#endif
44
45#if IBM
46#include <windows.h>
47#endif /* IBM */
48
49#define _LACF_GETLINE_INCLUDED
50#include "lacf_getline_impl.h"
51#define _LACF_PARSER_FUNCS_INCLUDED
52#include "parser_funcs.h"
53#include "math_core.h"
54#include "sysmacros.h"
55#include "safe_alloc.h"
56#include "time.h"
57#include "types.h"
58
59#ifdef __cplusplus
60extern "C" {
61#endif
62
77#define IS_VALID_GEO_POS3(pos) \
78 (is_valid_lat((pos).lat) && is_valid_lon((pos).lon) && \
79 is_valid_elev((pos).elev))
86#define IS_VALID_GEO_POS2(pos) \
87 (is_valid_lat((pos).lat) && is_valid_lon((pos).lon))
92static inline bool_t
93is_valid_lat(double lat)
94{
95 return (!isnan(lat) && fabs(lat) <= 90);
96}
101static inline bool_t
103{
104 return (!isnan(lat) && fabs(lat) <= 90);
105}
110static inline bool_t
111is_valid_lon(double lon)
112{
113 return (!isnan(lon) && fabs(lon) <= 180.0);
114}
122static inline bool_t
123is_valid_elev(double elev)
124{
125 return (!isnan(elev) && elev >= MIN_ELEV && elev <= MAX_ELEV);
126}
127
128#ifdef LACF_ENABLE_LEGACY_IS_VALID_ALT
129#define is_valid_alt(alt) is_valid_alt_ft(alt)
130#endif
138static inline bool_t
139is_valid_alt_ft(double alt_ft)
140{
141 return (!isnan(alt_ft) && alt_ft >= MIN_ALT && alt_ft <= MAX_ALT);
142}
148static inline bool_t
149is_valid_alt_m(double alt_m)
150{
151 return (!isnan(alt_m) && alt_m >= MIN_ALT / 3.2808398950131 &&
152 alt_m <= MAX_ALT / 3.2808398950131);
153}
159static inline bool_t
160is_valid_spd(double spd)
161{
162 return (!isnan(spd) && spd >= 0.0 && spd <= MAX_SPD);
163}
168static inline bool_t
169is_valid_hdg(double hdg)
170{
171 return (!isnan(hdg) && hdg >= 0.0 && hdg <= 360.0);
172}
198#define rel_hdg(hdg1, hdg2) rel_hdg_impl(hdg1, hdg2, __FILE__, __LINE__)
199API_EXPORT double rel_hdg_impl(double hdg1, double hdg2, const char *file,
200 int line);
201
214static inline double
215normalize_hdg(double hdg)
216{
217 if (isnan(hdg))
218 return (hdg);
219 hdg = fmod(hdg, 360);
220 /* Flip negative into positive */
221 if (hdg < 0.0)
222 hdg += 360.0;
223 /* Necessary to avoid FP rounding errors */
224 if (hdg <= 0.0 || hdg > 360.0) {
225 hdg = clamp(hdg, 0, 360);
226 /* Avoid negative zero */
227 if (hdg == -0.0)
228 hdg = 0.0;
229 }
230 return (hdg);
231}
232
245static inline double
246normalize_hdg_rad(double hdg_rad)
247{
248 if (isnan(hdg_rad)) {
249 return (hdg_rad);
250 }
251 hdg_rad = fmod(hdg_rad, 360);
252 /* Flip negative into positive */
253 if (hdg_rad < 0.0) {
254 hdg_rad += 2.0 * M_PI;
255 }
256 /* Necessary to avoid FP rounding errors */
257 if (hdg_rad <= 0.0 || hdg_rad > 2.0 * M_PI) {
258 hdg_rad = clamp(hdg_rad, 0, 2.0 * M_PI);
259 /* Avoid negative zero */
260 if (hdg_rad == -0.0) {
261 hdg_rad = 0.0;
262 }
263 }
264 return (hdg_rad);
265}
266
278static inline double
279normalize_lon(double lon)
280{
281 while (lon > 180.0)
282 lon -= 360.0;
283 while (lon < -180.0)
284 lon += 360.0;
285 return (clamp(lon, -180, 180));
286}
287
288API_EXPORT bool_t is_valid_icao_code(const char *icao);
289API_EXPORT bool_t is_valid_iata_code(const char *iata);
290API_EXPORT const char *extract_icao_country_code(const char *icao);
291
292API_EXPORT bool_t is_valid_xpdr_code(int code);
293API_EXPORT bool_t is_valid_vor_freq(double freq_mhz);
299static inline bool_t
300is_valid_vor_freq_hz(uint32_t freq_hz)
301{
302 return (is_valid_vor_freq(freq_hz / 1000000.0));
303}
309static inline bool_t
310is_valid_vor_freq_khz(uint32_t freq_khz)
311{
312 return (is_valid_vor_freq(freq_khz / 1000.0));
313}
314
315API_EXPORT bool_t is_valid_loc_freq(double freq_mhz);
321static inline bool_t
322is_valid_loc_freq_hz(uint32_t freq_hz)
323{
324 return (is_valid_loc_freq(freq_hz / 1000000.0));
325}
331static inline bool_t
332is_valid_loc_freq_khz(uint32_t freq_khz)
333{
334 return (is_valid_loc_freq(freq_khz / 1000.0));
335}
336
337API_EXPORT bool_t is_valid_ndb_freq(double freq_khz);
343static inline bool_t is_valid_ndb_freq_hz(uint32_t freq_hz)
344{
345 return (is_valid_ndb_freq(freq_hz / 1000.0));
346}
347
348API_EXPORT bool_t is_valid_tacan_freq(double freq_mhz);
349API_EXPORT bool_t is_valid_rwy_ID(const char *rwy_ID);
350API_EXPORT void copy_rwy_ID(const char *src, char dst[4]);
351
352/* AIRAC date functions */
353API_EXPORT const char *airac_cycle2eff_date(int cycle);
354API_EXPORT time_t airac_cycle2eff_date2(int cycle);
355API_EXPORT bool_t airac_cycle2exp_date(int cycle, char buf[16],
356 time_t *cycle_end_p);
357API_EXPORT int airac_time2cycle(time_t t);
358
359/* CSV file & string processing helpers */
386UNUSED_ATTR static ssize_t
387parser_get_next_line(FILE *fp, char **linep, size_t *linecap, unsigned *linenum)
388{
389#if defined(ACFUTILS_BUILD) || defined(ACFUTILS_GZIP_PARSER)
390 return (parser_get_next_line_impl(fp, linep, linecap, linenum,
391 B_FALSE));
392#else /* !defined(ACFUTILS_BUILD) && !defined(ACFUTILS_GZIP_PARSER) */
393 return (parser_get_next_line_impl(fp, linep, linecap, linenum));
394#endif /* !defined(ACFUTILS_BUILD) && !defined(ACFUTILS_GZIP_PARSER) */
395}
396
397#if defined(ACFUTILS_BUILD) || defined(ACFUTILS_GZIP_PARSER)
398/*
399 * Same as parser_get_next_line, but for gzip-compressed files.
400 */
401UNUSED_ATTR static ssize_t
402parser_get_next_gzline(void *gz_fp, char **linep, size_t *linecap,
403 unsigned *linenum)
404{
405 return (parser_get_next_line_impl(gz_fp, linep, linecap, linenum,
406 B_TRUE));
407}
408#endif /* defined(ACFUTILS_BUILD) || defined(ACFUTILS_GZIP_PARSER) */
409
415UNUSED_ATTR static char *
417{
418 return (parser_get_next_quoted_str2(fp, NULL));
419}
420
421API_EXPORT ssize_t explode_line(char *line, char delim, char **comps,
422 size_t capacity);
423API_EXPORT void append_format(char **str, size_t *sz,
424 PRINTF_FORMAT(const char *format), ...) PRINTF_ATTR(3);
433static inline void
435{
436 for (int i = 0, n = strlen(str); i < n; i++) {
437 if (isspace(str[i]))
438 str[i] = ' ';
439 }
440}
441
442/* string processing helpers */
443API_EXPORT char **strsplit(const char *input, const char *sep,
444 bool_t skip_empty, size_t *num);
450#define DESTROY_STRLIST(comps, num) \
451 do { \
452 free_strlist((comps), (num)); \
453 (comps) = NULL; \
454 (num) = 0; \
455 } while (0)
456API_EXPORT void free_strlist(char **comps, size_t num);
457API_EXPORT void unescape_percent(char *str);
458
459API_EXPORT char *mkpathname(const char *comp, ...) SENTINEL_ATTR;
460API_EXPORT char *mkpathname_v(const char *comp, va_list ap);
461API_EXPORT void fix_pathsep(char *str);
462
463API_EXPORT char *path_last_comp_subst(const char *path, const char *replace);
464API_EXPORT char *path_last_comp(const char *path);
465API_EXPORT char *path_ext_subst(const char *path, const char *ext);
466API_EXPORT void path_normalize(char *path);
467
468API_EXPORT char *file2str(const char *comp, ...) SENTINEL_ATTR;
469API_EXPORT char *file2str_ext(long *len_p, const char *comp, ...) SENTINEL_ATTR;
470API_EXPORT char *file2str_name(long *len_p, const char *filename);
471API_EXPORT void *file2buf(const char *filename, size_t *bufsz);
472API_EXPORT ssize_t filesz(const char *filename);
473
474/*
475 * strlcpy is a BSD function not available on Windows, so we roll a simple
476 * version of it ourselves. Can't inline this function, because GCC's fucked
477 * up array bounds checker will squawk endlessly when this is used to copy
478 * strings to a fixed-size array.
479 */
480#if IBM || LIN
481#define strlcpy lacf_strlcpy
482#endif
483API_EXPORT void lacf_strlcpy(char *restrict dest, const char *restrict src,
484 size_t cap);
485
490static inline const char *
491lacf_basename(const char *str)
492{
493 const char *sep = strrchr(str, DIRSEP);
494
495#if IBM
496 const char *sep2 = strrchr(str, '/');
497 if (sep2 > sep)
498 sep = sep2;
499#endif /* IBM */
500
501 if (sep == NULL)
502 return (str);
503 return (&sep[1]);
504}
505
510UNUSED_ATTR static ssize_t
511lacf_getline(char **lineptr, size_t *n, FILE *stream)
512{
513#if defined(ACFUTILS_BUILD) || defined(ACFUTILS_GZIP_PARSER)
514 return (lacf_getline_impl(lineptr, n, stream, B_FALSE));
515#else
516 return (lacf_getline_impl(lineptr, n, stream));
517#endif
518}
519
520#if IBM && !defined(__cplusplus) && \
521 (defined(_GNU_SOURCE) || defined(_POSIX_C_SOURCE))
522#define getline lacf_getline
523#endif
524
525API_EXPORT void strtolower(char *str);
526API_EXPORT void strtoupper(char *str);
527
539static inline char *
540vsprintf_alloc(const char *fmt, va_list ap)
541{
542 va_list ap2;
543 int l;
544 char *str;
545
546 ASSERT(fmt != NULL);
547
548 va_copy(ap2, ap);
549 l = vsnprintf(NULL, 0, fmt, ap2);
550 va_end(ap2);
551
552 ASSERT(l >= 0);
553 str = (char *)safe_malloc(l + 1);
554 (void)vsnprintf(str, l + 1, fmt, ap);
555
556 return (str);
557}
558
571PRINTF_ATTR(1) static inline char *
572sprintf_alloc(PRINTF_FORMAT(const char *fmt), ...)
573{
574 va_list ap;
575 char *str;
576
577 ASSERT(fmt != NULL);
578
579 va_start(ap, fmt);
580 str = vsprintf_alloc(fmt, ap);
581 va_end(ap);
582
583 return (str);
584}
585
592static inline int
593lacf_strncasecmp(const char *s1, const char *s2, size_t n)
594{
595 int l1, l2, res;
596 enum { STACKBUFSZ_LIM = 1024 };
597
598 ASSERT(s1 != NULL);
599 ASSERT(s2 != NULL);
600
601 l1 = strlen(s1);
602 l2 = strlen(s2);
603
604 if (l1 < STACKBUFSZ_LIM && l2 < STACKBUFSZ_LIM) {
605 char s1_lower[STACKBUFSZ_LIM], s2_lower[STACKBUFSZ_LIM];
606
607 lacf_strlcpy(s1_lower, s1, sizeof (s1_lower));
608 lacf_strlcpy(s2_lower, s2, sizeof (s2_lower));
609 strtolower(s1_lower);
610 strtolower(s2_lower);
611 res = strncmp(s1_lower, s2_lower, n);
612 } else {
613 char *s1_lower = (char *)safe_malloc(l1 + 1);
614 char *s2_lower = (char *)safe_malloc(l2 + 1);
615
616 lacf_strlcpy(s1_lower, s1, l1 + 1);
617 lacf_strlcpy(s2_lower, s2, l2 + 1);
618 strtolower(s1_lower);
619 strtolower(s2_lower);
620 res = strncmp(s1_lower, s2_lower, n);
621 free(s1_lower);
622 free(s2_lower);
623 }
624 return (res);
625}
626
633static inline int
634lacf_strcasecmp(const char *s1, const char *s2)
635{
636 return (lacf_strncasecmp(s1, s2, MAX(strlen(s1), strlen(s2))));
637}
638
644static inline char *
645lacf_strcasestr(const char *haystack, const char *needle)
646{
647 int l1, l2;
648 char *res;
649 enum { STACKBUFSZ_LIM = 1024 };
650
651 ASSERT(haystack != NULL);
652 ASSERT(needle != NULL);
653
654 l1 = strlen(haystack);
655 l2 = strlen(needle);
656
657 if (l1 < STACKBUFSZ_LIM && l2 < STACKBUFSZ_LIM) {
658 char haystack_lower[STACKBUFSZ_LIM];
659 char needle_lower[STACKBUFSZ_LIM];
660
661 lacf_strlcpy(haystack_lower, haystack, sizeof (haystack_lower));
662 lacf_strlcpy(needle_lower, needle, sizeof (needle_lower));
663 strtolower(haystack_lower);
664 strtolower(needle_lower);
665 res = strstr(haystack_lower, needle_lower);
666 if (res != NULL)
667 res = (char *)haystack + (res - haystack_lower);
668 } else {
669 char *haystack_lower = (char *)safe_malloc(l1 + 1);
670 char *needle_lower = (char *)safe_malloc(l2 + 1);
671
672 lacf_strlcpy(haystack_lower, haystack, l1 + 1);
673 lacf_strlcpy(needle_lower, needle, l2 + 1);
674 strtolower(haystack_lower);
675 strtolower(needle_lower);
676 res = strstr(haystack_lower, needle_lower);
677 if (res != NULL)
678 res = (char *)haystack + (res - haystack_lower);
679 free(haystack_lower);
680 free(needle_lower);
681 }
682 return (res);
683}
684
717static inline int
718fixed_decimals(double x, int digits)
719{
720 if (x > -1e-10 && x < 1e-10)
721 return (MAX(digits - 1, 0));
722 if (x < 0)
723 x *= -1;
724 /* This avoids the leading "0." not counting to the digit number */
725 if (x < 1)
726 digits = MAX(digits - 1, 0);
727 return (clampi(digits - ceil(log10(x)), 0, digits));
728}
729
730API_EXPORT size_t utf8_char_get_num_bytes(const char *str);
731API_EXPORT size_t utf8_get_num_chars(const char *str);
732
736#define P2ROUNDUP(x) (-(-(x) & -(1 << highbit64(x))))
738static inline double
739roundmul(double x, double y)
740{
741 return (round(x / y) * y);
742}
744static inline double
745floormul(double x, double y)
746{
747 return (floor(x / y) * y);
748}
779#define SET_BITFIELD_1(out_var, bit_mask, bit_value) \
780 do { \
781 if (bit_value) \
782 (out_var) |= (bit_mask); \
783 else \
784 (out_var) &= ~(bit_mask); \
785 } while (0)
786
787/* file/directory manipulation */
788API_EXPORT bool_t file_exists(const char *path, bool_t *isdir);
789API_EXPORT bool_t create_directory(const char *dirname);
790API_EXPORT bool_t create_directory_recursive(const char *dirname);
791API_EXPORT bool_t remove_directory(const char *dirname);
792API_EXPORT bool_t remove_file(const char *filename, bool_t notfound_ok);
793
794API_EXPORT char *lacf_dirname(const char *filename);
795
796#if IBM && (defined(_GNU_SOURCE) || defined(_POSIX_C_SOURCE))
797
798/* A minimally compatible POSIX-style directory reading implementation */
799struct dirent {
800 char d_name[256];
801};
802typedef struct {
803 HANDLE handle;
804 WIN32_FIND_DATA find_data;
805 bool_t first;
806 struct dirent de;
807} DIR;
808
809API_EXPORT DIR *opendir(const char *path);
810API_EXPORT struct dirent *readdir(DIR *dirp);
811API_EXPORT void closedir(DIR *dirp);
812
813#define sleep(x) SleepEx((x) * 1000, FALSE)
814#define usleep(x) SleepEx((x) / 1000, FALSE)
815
816#endif /* IBM && (defined(_GNU_SOURCE) || defined(_POSIX_C_SOURCE)) */
817
818#if IBM
819
820API_EXPORT void win_perror(DWORD err, PRINTF_FORMAT(const char *fmt), ...)
821 PRINTF_ATTR(2);
822
823#endif /* IBM */
824
825API_EXPORT void lacf_qsort_r(void *base, size_t nmemb, size_t size,
826 int (*compar)(const void *, const void *, void *), void *arg);
827
845static inline bool_t
846lacf_gmtime_r(const time_t *tim, struct tm *tm)
847{
848#if defined(__STDC_LIB_EXT1__) || IBM
849 return (_gmtime64_s(tm, tim) == 0);
850#else /* !defined(__STDC_LIB_EXT1__) && !IBM */
851 return (gmtime_r(tim, tm) != NULL);
852#endif /* !defined(__STDC_LIB_EXT1__) && !IBM */
853}
854
855
856#ifdef __cplusplus
857}
858#endif
859
860#endif /* _ACF_UTILS_HELPERS_H_ */
#define ASSERT(x)
Definition assert.h:208
#define UNUSED_ATTR
Definition core.h:95
char * file2str_name(long *len_p, const char *filename)
Definition helpers.c:1087
static int fixed_decimals(double x, int digits)
Definition helpers.h:718
char * lacf_dirname(const char *filename)
Definition helpers.c:1489
char ** strsplit(const char *input, const char *sep, bool_t skip_empty, size_t *num)
Definition helpers.c:650
static bool_t is_valid_spd(double spd)
Definition helpers.h:160
ssize_t filesz(const char *filename)
Definition helpers.c:1174
void unescape_percent(char *str)
Definition helpers.c:753
int airac_time2cycle(time_t t)
Definition helpers.c:557
static ssize_t lacf_getline(char **lineptr, size_t *n, FILE *stream)
Definition helpers.h:511
void fix_pathsep(char *str)
Definition helpers.c:892
char * mkpathname(const char *comp,...)
Definition helpers.c:833
void strtoupper(char *str)
Definition helpers.c:783
char * path_ext_subst(const char *path, const char *ext)
Definition helpers.c:973
void copy_rwy_ID(const char *src, char dst[4])
Definition helpers.c:411
char * file2str(const char *comp,...)
Definition helpers.c:1036
bool_t remove_directory(const char *dirname)
Definition helpers.c:1382
bool_t is_valid_icao_code(const char *icao)
Definition helpers.c:312
ssize_t explode_line(char *line, char delim, char **comps, size_t capacity)
Definition helpers.c:588
void path_normalize(char *path)
Definition helpers.c:1013
static bool_t lacf_gmtime_r(const time_t *tim, struct tm *tm)
Definition helpers.h:846
size_t utf8_get_num_chars(const char *str)
Definition helpers.c:816
static bool_t is_valid_loc_freq_khz(uint32_t freq_khz)
Definition helpers.h:332
static int lacf_strncasecmp(const char *s1, const char *s2, size_t n)
Definition helpers.h:593
static bool_t is_valid_alt_ft(double alt_ft)
Definition helpers.h:139
bool_t is_valid_loc_freq(double freq_mhz)
Definition helpers.c:261
static ssize_t parser_get_next_line(FILE *fp, char **linep, size_t *linecap, unsigned *linenum)
Definition helpers.h:387
char * file2str_ext(long *len_p, const char *comp,...)
Definition helpers.c:1055
const char * extract_icao_country_code(const char *icao)
Definition helpers.c:358
static bool_t is_valid_elev(double elev)
Definition helpers.h:123
static bool_t is_valid_vor_freq_khz(uint32_t freq_khz)
Definition helpers.h:310
bool_t is_valid_vor_freq(double freq_mhz)
Definition helpers.c:233
bool_t is_valid_ndb_freq(double freq_khz)
Definition helpers.c:297
static bool_t is_valid_hdg(double hdg)
Definition helpers.h:169
static char * sprintf_alloc(const char *fmt,...)
Definition helpers.h:572
const char * airac_cycle2eff_date(int cycle)
Definition helpers.c:485
bool_t create_directory(const char *dirname)
Definition helpers.c:1261
bool_t is_valid_tacan_freq(double freq_mhz)
Definition helpers.c:280
void * file2buf(const char *filename, size_t *bufsz)
Definition helpers.c:1134
static char * vsprintf_alloc(const char *fmt, va_list ap)
Definition helpers.h:540
bool_t airac_cycle2exp_date(int cycle, char buf[16], time_t *cycle_end_p)
Definition helpers.c:526
static double normalize_hdg(double hdg)
Definition helpers.h:215
static int lacf_strcasecmp(const char *s1, const char *s2)
Definition helpers.h:634
static const char * lacf_basename(const char *str)
Definition helpers.h:491
void append_format(char **str, size_t *sz, const char *format,...)
Definition helpers.c:731
void lacf_qsort_r(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *, void *), void *arg)
Definition helpers.c:1650
void lacf_strlcpy(char *dest, const char *src, size_t cap)
Definition helpers.c:1667
void free_strlist(char **comps, size_t num)
Definition helpers.c:703
double rel_hdg_impl(double hdg1, double hdg2, const char *file, int line)
Definition helpers.c:194
size_t utf8_char_get_num_bytes(const char *str)
Definition helpers.c:797
bool_t create_directory_recursive(const char *dirname)
Definition helpers.c:1292
bool_t is_valid_rwy_ID(const char *rwy_ID)
Definition helpers.c:379
static void normalize_whitespace(char *str)
Definition helpers.h:434
char * path_last_comp(const char *path)
Definition helpers.c:952
void strtolower(char *str)
Definition helpers.c:773
static bool_t is_valid_lat(double lat)
Definition helpers.h:93
bool_t remove_file(const char *filename, bool_t notfound_ok)
Definition helpers.c:1459
time_t airac_cycle2eff_date2(int cycle)
Definition helpers.c:499
static double normalize_lon(double lon)
Definition helpers.h:279
bool_t is_valid_xpdr_code(int code)
Definition helpers.c:217
static bool_t is_valid_ndb_freq_hz(uint32_t freq_hz)
Definition helpers.h:343
static bool_t is_valid_alt_m(double alt_m)
Definition helpers.h:149
static bool_t is_valid_vor_freq_hz(uint32_t freq_hz)
Definition helpers.h:300
static char * parser_get_next_quoted_str(FILE *fp)
Definition helpers.h:416
static bool_t is_valid_lat_polar(double lat)
Definition helpers.h:102
static double roundmul(double x, double y)
Definition helpers.h:739
char * mkpathname_v(const char *comp, va_list ap)
Definition helpers.c:850
bool_t file_exists(const char *path, bool_t *isdir)
Definition helpers.c:1222
static bool_t is_valid_lon(double lon)
Definition helpers.h:111
static double normalize_hdg_rad(double hdg_rad)
Definition helpers.h:246
bool_t is_valid_iata_code(const char *iata)
Definition helpers.c:336
char * path_last_comp_subst(const char *path, const char *replace)
Definition helpers.c:924
static double floormul(double x, double y)
Definition helpers.h:745
static bool_t is_valid_loc_freq_hz(uint32_t freq_hz)
Definition helpers.h:322
static char * lacf_strcasestr(const char *haystack, const char *needle)
Definition helpers.h:645
static ssize_t lacf_getline_impl(char **line_p, size_t *cap_p, void *fp)
static double clamp(double x, double min_val, double max_val)
Definition math_core.h:60
static int clampi(int x, int min_val, int max_val)
Definition math_core.h:68
static char * parser_get_next_quoted_str2(FILE *fp, int *linep)
static ssize_t parser_get_next_line_impl(void *fp, char **linep, size_t *linecap, unsigned *linenum)
static void * safe_malloc(size_t size)
Definition safe_alloc.h:56