libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
|
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <math.h>
#include "lacf_getline_impl.h"
#include "parser_funcs.h"
#include "math_core.h"
#include "sysmacros.h"
#include "safe_alloc.h"
#include "time.h"
#include "types.h"
Go to the source code of this file.
Macros | |
#define | _LACF_GETLINE_INCLUDED |
#define | _LACF_PARSER_FUNCS_INCLUDED |
#define | IS_VALID_GEO_POS3(pos) |
#define | IS_VALID_GEO_POS2(pos) (is_valid_lat((pos).lat) && is_valid_lon((pos).lon)) |
#define | rel_hdg(hdg1, hdg2) rel_hdg_impl(hdg1, hdg2, __FILE__, __LINE__) |
#define | DESTROY_STRLIST(comps, num) |
#define | P2ROUNDUP(x) (-(-(x) & -(1 << highbit64(x)))) |
#define | SET_BITFIELD_1(out_var, bit_mask, bit_value) |
Functions | |
static bool_t | is_valid_lat (double lat) |
static bool_t | is_valid_lat_polar (double lat) |
static bool_t | is_valid_lon (double lon) |
static bool_t | is_valid_elev (double elev) |
static bool_t | is_valid_alt_ft (double alt_ft) |
static bool_t | is_valid_alt_m (double alt_m) |
static bool_t | is_valid_spd (double spd) |
static bool_t | is_valid_hdg (double hdg) |
double | rel_hdg_impl (double hdg1, double hdg2, const char *file, int line) |
static double | normalize_hdg (double hdg) |
static double | normalize_hdg_rad (double hdg_rad) |
static double | normalize_lon (double lon) |
bool_t | is_valid_icao_code (const char *icao) |
bool_t | is_valid_iata_code (const char *iata) |
const char * | extract_icao_country_code (const char *icao) |
bool_t | is_valid_xpdr_code (int code) |
bool_t | is_valid_vor_freq (double freq_mhz) |
static bool_t | is_valid_vor_freq_hz (uint32_t freq_hz) |
static bool_t | is_valid_vor_freq_khz (uint32_t freq_khz) |
bool_t | is_valid_loc_freq (double freq_mhz) |
static bool_t | is_valid_loc_freq_hz (uint32_t freq_hz) |
static bool_t | is_valid_loc_freq_khz (uint32_t freq_khz) |
bool_t | is_valid_ndb_freq (double freq_khz) |
static bool_t | is_valid_ndb_freq_hz (uint32_t freq_hz) |
bool_t | is_valid_tacan_freq (double freq_mhz) |
bool_t | is_valid_rwy_ID (const char *rwy_ID) |
void | copy_rwy_ID (const char *src, char dst[4]) |
const char * | airac_cycle2eff_date (int cycle) |
time_t | airac_cycle2eff_date2 (int cycle) |
bool_t | airac_cycle2exp_date (int cycle, char buf[16], time_t *cycle_end_p) |
int | airac_time2cycle (time_t t) |
static ssize_t | parser_get_next_line (FILE *fp, char **linep, size_t *linecap, unsigned *linenum) |
static char * | parser_get_next_quoted_str (FILE *fp) |
ssize_t | explode_line (char *line, char delim, char **comps, size_t capacity) |
void | append_format (char **str, size_t *sz, const char *format,...) |
static void | normalize_whitespace (char *str) |
char ** | strsplit (const char *input, const char *sep, bool_t skip_empty, size_t *num) |
void | free_strlist (char **comps, size_t num) |
void | unescape_percent (char *str) |
char * | mkpathname (const char *comp,...) |
char * | mkpathname_v (const char *comp, va_list ap) |
void | fix_pathsep (char *str) |
char * | path_last_comp_subst (const char *path, const char *replace) |
char * | path_last_comp (const char *path) |
char * | path_ext_subst (const char *path, const char *ext) |
void | path_normalize (char *path) |
char * | file2str (const char *comp,...) |
char * | file2str_ext (long *len_p, const char *comp,...) |
char * | file2str_name (long *len_p, const char *filename) |
void * | file2buf (const char *filename, size_t *bufsz) |
ssize_t | filesz (const char *filename) |
void | lacf_strlcpy (char *dest, const char *src, size_t cap) |
static const char * | lacf_basename (const char *str) |
static ssize_t | lacf_getline (char **lineptr, size_t *n, FILE *stream) |
void | strtolower (char *str) |
void | strtoupper (char *str) |
static char * | vsprintf_alloc (const char *fmt, va_list ap) |
static char * | sprintf_alloc (const char *fmt,...) |
static int | lacf_strncasecmp (const char *s1, const char *s2, size_t n) |
static int | lacf_strcasecmp (const char *s1, const char *s2) |
static char * | lacf_strcasestr (const char *haystack, const char *needle) |
static int | fixed_decimals (double x, int digits) |
size_t | utf8_char_get_num_bytes (const char *str) |
size_t | utf8_get_num_chars (const char *str) |
static double | roundmul (double x, double y) |
static double | floormul (double x, double y) |
bool_t | file_exists (const char *path, bool_t *isdir) |
bool_t | create_directory (const char *dirname) |
bool_t | create_directory_recursive (const char *dirname) |
bool_t | remove_directory (const char *dirname) |
bool_t | remove_file (const char *filename, bool_t notfound_ok) |
char * | lacf_dirname (const char *filename) |
void | lacf_qsort_r (void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *, void *), void *arg) |
static bool_t | lacf_gmtime_r (const time_t *tim, struct tm *tm) |
This file contains helper functions mostly concerned with text and string processing.
Definition in file helpers.h.
#define DESTROY_STRLIST | ( | comps, | |
num | |||
) |
Invokes the free_strlist() function on the macro arguments and then sets both arguments to NULL
and 0
respectively, to help prevent inadvertent reuse.
#define IS_VALID_GEO_POS2 | ( | pos | ) | (is_valid_lat((pos).lat) && is_valid_lon((pos).lon)) |
Same as IS_VALID_GEO_POS3(), but for 2-space geographic coordinates without elevation.
#define IS_VALID_GEO_POS3 | ( | pos | ) |
pos
is a validate geographic coordinate (the latitude, longitude and elevation are sensible values). This is using the is_valid_lat(), is_valid_lon() and is_valid_elev() functions. Please note that this only accepts elevation values between -2000 and +30000. If your elevations are in, e.g. feet, 30000 is a very low max elevation value to check against. In that case, you should use IS_VALID_GEO_POS2(), or write a custom check macro that uses the is_valid_alt_ft() check function instead. #define P2ROUNDUP | ( | x | ) | (-(-(x) & -(1 << highbit64(x)))) |
#define rel_hdg | ( | hdg1, | |
hdg2 | |||
) | rel_hdg_impl(hdg1, hdg2, __FILE__, __LINE__) |
Calculates relative heading from hdg1
to hdg2
. Both heading values MUST be valid headings (pass the is_valid_hdg() check), otherwise an assertion failure is triggered.
hdg1
to hdg2
"the shortest
way". That means, if hdg2
is "to the right" of hdg1
(i.e. less than +180 degrees), the return value is in the positive range of +0 to +180 inclusive. Conversely, if the target is to the left, the return value will be between -0 and -180 inclusive. Please note that due to angle wrapping, you cannot simply add the result of rel_hdg() onto another heading and expect the result to be valid, such as: new_hdg
could well be >360 or <0 in this case. To properly add headings together and end up with something that passes the is_valid_hdg() test again, you always want to re-normalize the result using normalize_hdg(): #define SET_BITFIELD_1 | ( | out_var, | |
bit_mask, | |||
bit_value | |||
) |
Helper macro to either set or reset a bit field in an integer.
out_var | The integer variable where the bitfield will be set or reset. |
bit_mask | A mask of the bitfield to be manipulated. These are the bits that will be set or reset. |
bit_value | An condition value. If non-zero, the bits in bit_mask will be set to 1 in out_var . If zero, the bits in bit_mask will be reset to 0 in out_var . |
A more natural way to use this macro is to use the return value of a check function the third argument:
const char * airac_cycle2eff_date | ( | int | cycle | ) |
Translates an AIRAC cycle number into a shorthand start date string, from which the AIRAC cycle becomes "effective."
cycle | The AIRAC cycle number, e.g. 2210. |
time_t airac_cycle2eff_date2 | ( | int | cycle | ) |
bool_t airac_cycle2exp_date | ( | int | cycle, |
char | buf[16], | ||
time_t * | cycle_end_p | ||
) |
Translates an AIRAC cycle into the end date, at which the cycle expires. That is the last day on which the cycle is still valid. This will always be the 1 day before the next cycle becomes effective.
cycle | The AIRAC cycle for which to determine the expiry date. |
buf | Optional output string, which will be filled with a short human-readable date description. For example, AIRAC cycle 2210 will return "02-NOV" here. If you don't need this, set this argument to NULL. |
cycle_end_p | Optional output parameter, which will be filled with the time_t (Unixtime) of the last second when the AIRAC cycle is still effective, i.e. 23:59:59 UTC of the last day of the AIRAC cycle. 1 second later, the next AIRAC cycle becomes effective. If you don't need this value, set this to NULL. |
B_TRUE
if the AIRAC cycle expiry time is known, B_FALSE
otherwise. int airac_time2cycle | ( | time_t | t | ) |
void append_format | ( | char ** | str, |
size_t * | sz, | ||
const char * | format, | ||
... | |||
) |
Appends a printf-like formatted string to the end of *str, reallocating the buffer as needed to contain it. The value of *str
is modified to point to the appropriately reallocated buffer.
You should free the string using lacf_free() when you are done.
void copy_rwy_ID | ( | const char * | src, |
char | dst[4] | ||
) |
Copies a runway identifier from an unknown source to a 4-character runway identifier buffer. This also performs the following transformations on the runway identifier:
The function performs no validity checking other than making sure that the output buffer is not overflown. The caller is responsible for validating the result after copy_rwy_ID() returns using is_valid_rwy_ID().
bool_t create_directory | ( | const char * | dirname | ) |
bool_t create_directory_recursive | ( | const char * | dirname | ) |
ssize_t explode_line | ( | char * | line, |
char | delim, | ||
char ** | comps, | ||
size_t | capacity | ||
) |
Breaks up a line into components delimited by a character.
line | The input line to break up. The buffer will be modified to insert NULs in between the components so that they can each be treated as a separate string. |
delim | The delimiter character (e.g. ','). |
comps | A list of pointers that will be set to point to the start of each substring. |
capacity | The component capacity of comps . If more input components are encountered than is space in comps , the array is not overflown. |
comps
array was too small, returns the number of components that would have been needed to process the input string fully as a negative value. const char * extract_icao_country_code | ( | const char * | icao | ) |
void * file2buf | ( | const char * | filename, |
size_t * | bufsz | ||
) |
Reads the contents of a file and returns them in a memory buffer. Please note that this function has no limit on the size of file it will read, so you must use it with care so as not to overload the memory subsystem by trying to read a giant file which won't fit into memory.
filename | The full path to the file to be read. |
bufsz | Mandatory return argument, which will be filled with the number of bytes in the file. |
NULL
instead and the errno
variable will contain the exact error which occurred. char * file2str | ( | const char * | comp, |
... | |||
) |
char * file2str_ext | ( | long * | len_p, |
const char * | comp, | ||
... | |||
) |
char * file2str_name | ( | long * | len_p, |
const char * | filename | ||
) |
Reads the contents of a file and returns them. Please note that this function should ONLY be used for text files which are less than 256MB in size. Use file2buf() to read larger files, or files containing binary data.
len_p | Mandatory return argument, which will be filled with the actual length of the file in bytes (minus a terminating NUL byte). This can be larger than a simple strlen() on the return value might suggest, if the file contains a stray NUL byte somewhere inside. |
filename | The full path to the file to be read. |
NULL
instead and the errno
variable will contain the exact error which occurred. bool_t file_exists | ( | const char * | filename, |
bool_t * | isdir | ||
) |
ssize_t filesz | ( | const char * | filename | ) |
filename
in bytes. If the file does not exist, or the size cannot be determined, this returns -1
instead. This function doesn't open the file for reading, so don't assume that filesz() returning a valid size indicates file read access. void fix_pathsep | ( | char * | str | ) |
For some inexplicable reason, on Windows X-Plane can return paths via the API which are a mixture of Windows- & Unix-style path separators. This function fixes that by flipping all path separators to the appropriate type used on the host OS. This also eliminates duplicate path separators, which tends to break Windows UNC path resolution.
|
static |
Calculates the number of digits after a decimal point for a printf format string to make the number appear with a fixed number of digits as a whole.
x | The input number that is to be formatted. This should be the same number as that which will be used in the printf format value. |
digits | The number of digits that the final number should have. |
Say we want a number to take up room for 4 digits, adding decimal digits after the point as necessary to padd the number:
For numbers greater than 9999, the final number will have more than 4 digits. Use the fixed_decimals() function to achieve the above effect in a printf format as follows:
|
static |
void free_strlist | ( | char ** | comps, |
size_t | num | ||
) |
|
static |
alt_ft
is a valid altitude value. That means the value is not NAN and is between MIN_ALT
(-2000) and MAX_ALT
(100000) inclusive. The range check is really just to make sure the value is within sensible limits.
|
static |
Variant of is_valid_alt_ft() but expects the input altitude to be in meters.
|
static |
elev
is a valid elevation value in meters. That means the value is not NAN and is between MIN_ELEV
(-2000) and MAX_ELEV
(30000) inclusive. The range check is really just to make sure the value is within sensible limits.
|
static |
bool_t is_valid_iata_code | ( | const char * | iata | ) |
bool_t is_valid_icao_code | ( | const char * | icao | ) |
|
static |
|
static |
bool_t is_valid_loc_freq | ( | double | freq_mhz | ) |
|
static |
Same as is_valid_loc_freq(), but takes an integer frequency in Hz instead of a floating-point value in MHz.
|
static |
Same as is_valid_loc_freq(), but takes an integer frequency in kHz instead of a floating-point value in MHz.
|
static |
bool_t is_valid_ndb_freq | ( | double | freq_khz | ) |
|
static |
Same as is_valid_ndb_freq(), but takes an integer frequency in Hz instead of a floating-point value in kHz.
bool_t is_valid_rwy_ID | ( | const char * | rwy_ID | ) |
Checks a runway ID for correct formatting. Runway IDs are 2- or 3-character strings conforming to the following format:
|
static |
bool_t is_valid_tacan_freq | ( | double | freq_mhz | ) |
freq_mhz
is a valid TACAN frequency. bool_t is_valid_vor_freq | ( | double | freq_mhz | ) |
|
static |
Same as is_valid_vor_freq(), but takes an integer frequency in Hz instead of a floating-point value in MHz.
|
static |
Same as is_valid_vor_freq(), but takes an integer frequency in kHz instead of a floating-point value in MHz.
bool_t is_valid_xpdr_code | ( | int | code | ) |
|
static |
Portable version of the POSIX basename() function.
char * lacf_dirname | ( | const char * | filename | ) |
|
static |
|
static |
This function is a portable and thread-safe version of the gmtime() function. The problem with plain standard C gmtime() is that it is not thread-safe, because the returned argument is a pointer into a shared memory buffer, allocated inside of the standard C library. As such, time calls occurring in other threads might clobber the buffer.
The lacf_gmtime_r() function calls the platform-specific thread-safe version of gmtime(). On macOS and Linux, this uses the gmtime_r() function, whereas on Windows, this uses the _gmtime64_s() function.
tim | Pointer to a time_t , which is to be converted. |
tm | Pointer to a struct tm structure, which will be filled with the broken-down UTC time corresponding to tim . |
void lacf_qsort_r | ( | void * | base, |
size_t | nmemb, | ||
size_t | size, | ||
int(*)(const void *, const void *, void *) | compar, | ||
void * | arg | ||
) |
|
static |
Portable version of BSD & POSIX strcasecmp(). This is a case-insensitive variant strcmp().
|
static |
Portable version of BSD & POSIX strcasestr(). This is a case-insensitive variant strstr().
void lacf_strlcpy | ( | char * | dest, |
const char * | src, | ||
size_t | cap | ||
) |
|
static |
Portable version of BSD & POSIX strncasecmp(). This is a case-insensitive variant strncmp().
char * mkpathname | ( | const char * | comp, |
... | |||
) |
Allocates a file path string from individual path components. The components are provided as separate filename arguments and the list needs to be terminated with a NULL argument. The returned string must be freed using lacf_free(). The path components are separated using the appropriate path separator for the host platform ('\' on Windows, '/' on macOS and Linux).
char * mkpathname_v | ( | const char * | comp, |
va_list | ap | ||
) |
|
static |
Renormalizes a heading value that lies outside of the 0-360 inclusive range. Basically this takes care of undoing "angle wrapping".
|
static |
Renormalizes a heading value that lies outside of the 0-2PI inclusive range. Basically this takes care of undoing "angle wrapping".
|
static |
Renormalizes a longitude value. This is similar to normalize_hdg(), but instead of resolving angle wrapping into the 0-360 range, this resolves the output to be between -180..+180 (inclusive):
|
static |
Converts all whitespace in a string into plain ASCII space characters. This allows for easier splitting of a string at whitespace boundaries using functions such as strsplit(). First run the input to be split through normalize_whitespace() to make sure that any tabs are converted into plain ASCII spaces first and then use strsplit() to separate the line using the " " separator as the field delimeter.
|
static |
Grabs the next non-empty, non-comment line from a file, having stripped away all leading and trailing whitespace. Any tab characters are also replaced with spaces. Comments are lines that start with a '#' character. Also, any text following a '#' on a line is stripped away and considered a comment.
This function is useful for writing a custom config file parser. It can also be used to consume X-Plane OBJ and similar files, or generally any text-based data file which uses '#' for comments. See also conf_create_empty(), conf_read_file() and the conf.h file for a fully-featured config system already included with libacfutils.
fp | File from which to retrieve the line. |
linep | Line buffer which will hold the new line. If the buffer pointer is set to NULL, it will be allocated. If it is not long enough, it will be expanded. |
linecap | The capacity of *linep. If set to zero a new buffer is allocated. |
linenum | The current line number. Will be advanced by 1 for each new line read. |
|
static |
Legacy bridge to parser_get_next_quoted_str2() function without the optional second argument.
char * path_ext_subst | ( | const char * | path, |
const char * | ext | ||
) |
Takes ‘path’ and substitutes its path extension (any characters following the last '.') with ext
. If the path doesn't contain a path extension, it is appended. The newly allocated path is returned to the caller. The caller is responsible for freeing this path using lacf_free().
char * path_last_comp | ( | const char * | path | ) |
char * path_last_comp_subst | ( | const char * | path, |
const char * | replace | ||
) |
Strips the last path component from path
and replaces with with replace
. Example:
The returned value must be freed using lacf_free().
void path_normalize | ( | char * | path | ) |
Locates all instances of '//', '\', '..' and '.' and eliminates them from the path, resolving directory returns as necessary. This also first flips all path separators to the platform-appropriate type using fix_pathsep(). The path
argument is modified in place.
double rel_hdg_impl | ( | double | hdg1, |
double | hdg2, | ||
const char * | file, | ||
int | line | ||
) |
bool_t remove_directory | ( | const char * | dirname | ) |
bool_t remove_file | ( | const char * | filename, |
bool_t | notfound_ok | ||
) |
Removes a single file.
filename | Full path to the file to be removed. Please note that this must be a file and not a directory. Use remove_directory() to remove directories instead. |
notfound_ok | If set to B_TRUE , the function will return with a success indication, even if the file doesn't exist. Otherwise, the file not existing is considered an error. |
B_TRUE
if removing the file was successful (or the file didn't exist, provided that notfound_ok
was set to B_TRUE
).
|
static |
|
static |
Convenience function which allocates a new string of sufficient storage to hold a printf-formatted string. This removes the need to run the standard library C sprintf once to find out the length of a string, allocate storage, and then run it again to fill the storage.
fmt | Format string conforming to printf() formatting syntax. The remaining arguments must match the requirements of the format string. |
char ** strsplit | ( | const char * | input, |
const char * | sep, | ||
bool_t | skip_empty, | ||
size_t * | num | ||
) |
Splits up an input string by a separator into individual components.
input | The input string to be split up. |
sep | The separator string. The function looks for sequences of sep in input and any portions of the input which occur between separators are split out. |
skip_empty | This flag indicates whether to skip empty components (i.e. two occurences of the separator string which are next to each other). If set to B_TRUE , the resulting array will not contain empty strings where two consecutive separators were in the input. |
num | A mandatory return parameter, which will be set to the number of components in the output array. |
Example usage with skip_empty
set to B_FALSE
:
Example of effect of skip_empty
argument:
void strtolower | ( | char * | str | ) |
void strtoupper | ( | char * | str | ) |
void unescape_percent | ( | char * | str | ) |
size_t utf8_char_get_num_bytes | ( | const char * | str | ) |
Given a pointer to a single UTF-8-encoded character, returns the number of bytes occupied by the character. Please note that this doesn't go through the entire string, but instead only looks at a single character. Use utf_get_num_chars() to count the number of characters in an entire UTF-8 string
size_t utf8_get_num_chars | ( | const char * | str | ) |
|
static |
Variant of sprintf_alloc(), but which takes a va_list argument list as its second argument, to allow nesting it in other variadic functions.
fmt | Format string conforming to printf() formatting syntax. The remaining arguments must match the requirements of the format string. |
ap | Argument list containing all the arguments required by fmt . |