C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
Utility functions

string manipulation, file handling, and error reporting. More...

Functions

unsigned long a_to_ul (const char *str)
 Converts a string to an unsigned long long integer, with support for suffixes K, M, and G for kilobytes, megabytes, and gigabytes respectively.
int a_toi (char *s, bool *a_toi_error)
 a safer alternative to atoi() for converting ASCII strings to integers.
bool base_name (char *buf, char *path)
 Returns the base name of a file specification.
size_t canonicalize_file_spec (char *spec)
 Removes quotes and trims at first space.
bool chrep (char *s, char old_chr, char new_chr)
 Replaces all occurrences of old_chr in s with new_chr in place.
int destroy_argv (int argc, char **argv)
 Deallocates memory allocated for argument strings in argv.
bool dir_name (char *buf, char *path)
 Returns the directory name of a file specification.
bool expand_tilde (char *str, int path_maxlen)
 Replaces "~/" in string with the user's home directory.
char * fdname (int fd, char *out_path)
 Retrieves the file path associated with a given file descriptor.
bool file_spec_name (char *file_name, char *fs)
 extracts the file name component of a file specification
bool file_spec_path (char *fp, char *fs)
 extracts the path component of a file specification
char * format_local_timestamp (time_t t, char *buf, size_t n)
 Formats a time_t as an ISO 8601 string in local time.
bool get_argp_doc_by_name (char *comment, const struct argp_option *options, const char *key_name)
 Retrieves the documentation string for a given key name from an argp options array.
char * get_ip_addresses (char *ip_str, int maxlen)
 Retrieves the IP addresses of the local machine and formats them into a string.
char * get_local_timestamp ()
 Returns the current local time as an ISO 8601 formatted string.
char * get_user_str (char *user_str, size_t maxlen)
 Retrieves the current user's name and UID, and formats it into a string.
bool is_directory (const char *path)
 Checks if the given path is a directory.
bool is_hex_str (char *str, int len)
 Validates that a string consists of exactly len hexadecimal digits.
bool is_newer (char *control, char *fut)
 Checks if the file specified by "fut" is newer than the file specified by "control".
bool is_symlink_to_dir (const char *path)
 Checks if the given path is a symbolic link to a directory.
bool is_valid_regex (const char *pattern)
 Checks if the given regular expression pattern is valid.
char * iso8601_time (char *buf, int n, time_t *t, bool local)
 Formats a struct tm as an ISO 8601 string.
bool locate_file_in_path (char *file_spec, char *file_name)
 Locates a file in the system PATH.
bool mk_dir (char *dir)
 If directory doesn't exist, make it.
bool normalize_file_spec (char *fs)
 replace backslashes with forward lashes
void open_cmenu_log ()
 Open new C-Menu log file.
bool parse_local_timestamp (const char *s, time_t *out)
 Parses an ISO 8601 timestamp string in local time and converts it to time_t.
char * rep_substring (const char *org_s, const char *tgt_s, const char *rep_s)
 Replace all occurrences of "tgt_s" in "org_s" with "rep_s".
size_t ssnprintf (char *buf, size_t buf_size, const char *format,...)
 ssnprintf was designed to be a safer alternative to snprintf.
bool str_subc (char *d, char *s, char ReplaceChr, char *Withstr, int l)
 Replaces "ReplaceChr" in "s" with "Withstr" in "d" won't copy more than "l" bytes to "d" Replaces all occurrences of a character in a string with another string, copying the result to a destination buffer.
int str_to_args (char **argv, char *arg_str, int max_args)
 Converts a string into an array of argument strings.
double str_to_double (char *s)
 converts string to double
bool str_to_lower (char *s)
 Converts a string to lowercase.
bool str_to_upper (char *s)
 Converts a string to uppercase.
size_t strip_ansi (char *d, char *s)
 Strips ANSI SGR escape sequences (ending in 'm') from string s to d.
bool strip_quotes (char *s)
 removes leading and trailing double quotes if present
bool stripz_quotes (char *s)
 removes leading and trailing double quotes if present
size_t strnlf (char *s, size_t max_len)
 terminates string with line feed
size_t strnz (char *s, size_t max_len)
 terminates string at New Line, Carriage Return, or max_len
size_t strnz__cat (char *d, const char *s, size_t max_len)
 safer alternative to strncat
size_t strnz__cpy (char *d, const char *s, size_t max_len)
 safer alternative to strncpy
char * strnz_dup (char *s, size_t l)
 Allocates memory for and duplicates string s up to length l or until line feed or carriage return.
size_t strz (char *s)
 Terminates string at new line or carriage return.
size_t trim (char *s)
 Trims leading and trailing spaces from string s in place.
bool trim_ext (char *buf, char *filename)
 trims the file extension from "filename" and copies the result to "buf"
bool trim_path (char *dir)
 Trims trailing spaces and slashes from directory path in place.
void ui_rect_set (UiRect *r, int y, int x, int h, int w)
 Set the properties of a UiRect structure.
bool unstr_hex_clr (char *dst, char *str)
 Validates that a string is a hex color code in the format "#RRGGBB".
bool verify_dir (char *spec, int imode)
 Verifies that the directory specified by "spec" exists and is accessible with the permissions specified by "imode".
bool verify_file (char *in_spec, int imode)
 Verifies that the file specified by "in_spec" exists and is accessible with the permissions specified by "imode".
int wccp_to_str (wchar_t cp, uint8_t *buffer)
 Converts a Unicode code point to a UTF-8 encoded string.
void write_cmenu_log (char *msg)
 Write message to C-Menu log file with timestamp.
void write_cmenu_log_nt (char *msg)
 Write message to C-Menu log file without timestamp.

Detailed Description

string manipulation, file handling, and error reporting.

These functions provide common operations such as trimming strings, converting case, safely copying and concatenating strings, verifying file and directory access, and locating files in the system PATH. They are designed to be robust and handle edge cases gracefully, making them useful for a wide range of applications.

Function Documentation

◆ a_to_ul()

unsigned long a_to_ul ( const char * str)

Converts a string to an unsigned long long integer, with support for suffixes K, M, and G for kilobytes, megabytes, and gigabytes respectively.

Parameters
str- string to convert
Returns
converted unsigned long long value, or 0 if str is nullptr, empty, or invalid

This function is useful for parsing human-readable file sizes or memory sizes that may include suffixes to indicate the scale of the value. If the string is invalid (e.g., contains non-numeric characters other than the optional suffix), this function returns 0. The caller must ensure that the input string is a valid representation of an unsigned long long integer with an optional suffix before calling this function.

Definition at line 793 of file futil.c.

793 {
794 char *endptr;
795 unsigned long value = (unsigned long)strtoull(str, &endptr, 10);
796 if (endptr == str)
797 return 0;
798 switch (tolower(*endptr)) {
799 case 'g':
800 return value * 1024ULL * 1024ULL * 1024ULL;
801 case 'm':
802 return value * 1024ULL * 1024ULL;
803 case 'k':
804 return value * 1024ULL;
805 default:
806 return value;
807 }
808}

◆ a_toi()

int a_toi ( char * s,
bool * a_toi_error )

a safer alternative to atoi() for converting ASCII strings to integers.

Parameters
sis the input string
a_toi_erroris a pointer to a boolean that will be set to true if an error occurs during conversion, or false if the conversion is successful.
Returns
converted integer value, or -1 if an error occurs

Accepts positive integers only. Sets a_toi_error to (-1) on error

Definition at line 769 of file futil.c.

769 {
770 int rc = -1;
771 *a_toi_error = false;
772 errno = 0;
773 if (s && *s != 0)
774 rc = (int)strtol(s, nullptr, 10);
775 if (rc < 0 || errno) {
776 rc = -1;
777 *a_toi_error = true;
778 }
779 return rc;
780}

Referenced by parse_ansi_str().

Here is the caller graph for this function:

◆ base_name()

bool base_name ( char * buf,
char * path )

Returns the base name of a file specification.

Parameters
buf- buffer to receive result
path- file specification
Returns
true if successful
Note
The caller is responsible for ensuring that "buf" has enough space to receive the result.

Definition at line 1123 of file futil.c.

1124 {
1125 if (!path || !*path || !buf)
1126 return false;
1127 char *s = path;
1128 char *d = buf;
1129 *d = '\0';
1130 while (*s) {
1131 if (*s == '/' || *s == '\\') {
1132 d = buf;
1133 } else {
1134 *d++ = *s;
1135 }
1136 s++;
1137 }
1138 *d = '\0';
1139 if (d == buf)
1140 return false;
1141 return true;

Referenced by build_prompt(), exec_objects(), form_exec_receiver(), form_process(), init_form_files(), init_pick_files(), main(), and view_init_input().

Here is the caller graph for this function:

◆ canonicalize_file_spec()

size_t canonicalize_file_spec ( char * spec)

Removes quotes and trims at first space.

Parameters
spec- file specification to canonicalize
Returns
length of resulting string

Definition at line 1341 of file futil.c.

1342 {
1343 if (spec == nullptr || *spec == '\0')
1344 return 0;
1345 char tmp_s[MAXLEN];
1346 char *s;
1347 s = spec;
1348 char *d;
1349 d = tmp_s;
1350 int l = 0;
1351 while (*s != '\0') {
1352 if (*s == ' ')
1353 break;
1354 if (*s == '\"' || *s == '\'') {
1355 s++;
1356 continue;
1357 ;
1358 }
1359 *d++ = *s++;
1360 l++;
1361 }
1362 *d = '\0';
1363 strnz__cpy(spec, tmp_s, MAXLEN - 1);
1364 l = strlen(spec);
1365 return l;
#define MAXLEN
Definition curskeys.c:15
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition futil.c:544

References strnz__cpy().

Referenced by locate_file_in_path(), verify_file(), and verify_spec_arg().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ chrep()

bool chrep ( char * s,
char old_chr,
char new_chr )

Replaces all occurrences of old_chr in s with new_chr in place.

Parameters
s- string to modify
old_chr- character to replace
new_chr- character to insert
Returns
true if successful or false if string s is null

Definition at line 750 of file futil.c.

750 {
751 if (s == nullptr)
752 return false;
753 while (*s != '\0') {
754 if (*s == old_chr)
755 *s = new_chr;
756 s++;
757 }
758 return true;
759}

Referenced by parse_menu_description().

Here is the caller graph for this function:

◆ destroy_argv()

int destroy_argv ( int argc,
char ** argv )

Deallocates memory allocated for argument strings in argv.

Parameters
argc- count of allocated vectors in argv
argv- array of pointers to arguments
Note
the caller must ensure that argc accurately reflects the number of allocated strings in argv, and that argv is not null. After calling this function, the pointers in argv will be set to nullptr to prevent dangling pointers.

Definition at line 494 of file futil.c.

494 {
495 for (int i = 0; i < argc; i++) {
496 if (argv[i] != nullptr) {
497 free(argv[i]);
498 argv[i] = nullptr;
499 }
500 }
501 argc = 0;
502 return argc;
503}

Referenced by destroy_init(), destroy_view(), display_pick_help(), enter_file_spec(), exec_objects(), form_engine(), form_exec_receiver(), form_process(), init_pick(), menu_cmd_processor(), new_pick_view(), parse_opt_args(), view_display_help(), and view_init_input().

Here is the caller graph for this function:

◆ dir_name()

bool dir_name ( char * buf,
char * path )

Returns the directory name of a file specification.

Parameters
buf- buffer to receive result
path- file specification
Returns
true if successful
Note
The caller is responsible for ensuring that "buf" has enough space to receive the result.

Definition at line 1149 of file futil.c.

1150 {
1151 if (!path || !*path || !buf)
1152 return false;
1153 char tmp_str[MAXLEN];
1154 strnz__cpy(tmp_str, path, MAXLEN);
1155 char *s = tmp_str;
1156 while (*s++)
1157 ;
1158 while (tmp_str < --s) {
1159 if (*s == '/' || *s == '\\') {
1160 *s = '\0';
1161 break;
1162 }
1163 }
1164 while (tmp_str < --s && (*s == '/' || *s == '\\'))
1165 *s = '\0';
1166 char *d = buf;
1167 *d = '\0';
1168 s = tmp_str;
1169 while (*s) {
1170 *d++ = *s++;
1171 }
1172 *d = '\0';
1173 if (d == buf)
1174 return false;
1175 return true;

References strnz__cpy().

Here is the call graph for this function:

◆ expand_tilde()

bool expand_tilde ( char * str,
int path_maxlen )

Replaces "~/" in string with the user's home directory.

Parameters
str- string to modify
path_maxlen- maximum length of resulting string
Returns
true if successful, false if str is nullptr or empty

Definition at line 970 of file futil.c.

971 {
972 if (str == nullptr || *str == '\0')
973 return false;
974 const char tgt[3] = "~/";
975 char path[MAXLEN];
976 char *e = getenv("HOME");
977 strnz__cpy(path, e, MAXLEN - 1);
978 strnz__cat(path, "/", MAXLEN - 1);
979 char *tmp;
980 tmp = rep_substring(str, tgt, path);
981 strnz__cpy(str, tmp, path_maxlen - 1);
982 free(tmp);
983 return true;
size_t strnz__cat(char *, const char *, size_t)
safer alternative to strncat
Definition futil.c:573
char * rep_substring(const char *, const char *, const char *)
Replace all occurrences of "tgt_s" in "org_s" with "rep_s".
Definition futil.c:1440

References rep_substring(), strnz__cat(), and strnz__cpy().

Referenced by enter_file_spec(), init_form_files(), init_pick_files(), init_view_files(), main(), mapp_initialization(), mk_dir(), process_config_file(), process_config_files(), read_theme(), verify_dir(), verify_file(), verify_spec_arg(), and view_init_input().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fdname()

char * fdname ( int fd,
char * out_path )

Retrieves the file path associated with a given file descriptor.

Parameters
fd- file descriptor
out_path- buffer to receive the file path
Returns
0 on success, -1 on failure

This function uses the /proc filesystem to read the symbolic link corresponding to the file descriptor. It constructs the path to the symbolic link in /proc/self/fd/ and uses readlink to retrieve the actual file path. The caller must ensure that out_path has enough space to hold the resulting path. If readlink fails, this function returns -1 and does not modify out_path.

Definition at line 1054 of file futil.c.

1055 {
1056 char proc_path[MAXLEN];
1057
1058 snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", fd);
1059 ssize_t len = readlink(proc_path, out_path, MAXLEN - 1);
1060 if (len == -1)
1061 return nullptr;
1062 out_path[len] = '\0';
1063 return out_path;

Referenced by stdio_fdnames().

Here is the caller graph for this function:

◆ file_spec_name()

bool file_spec_name ( char * file_name,
char * fs )

extracts the file name component of a file specification

Parameters
file_name- name component to return
fs- full file specification
Note
The caller is responsible for ensuring that "file_name" has enough space to receive the result.

Definition at line 897 of file futil.c.

898 {
899 if (fs == nullptr || *fs == '\0' || file_name == nullptr) {
900 if (file_name != nullptr)
901 *file_name = '\0';
902 return false;
903 }
904 char *d, *l, *s;
905 l = nullptr;
906 s = fs;
907 while (*s != '\0') {
908 if (*s == '/')
909 l = s;
910 s++;
911 }
912 if (l == nullptr)
913 s = fs;
914 else
915 s = ++l;
916 d = file_name;
917 while (*s != '\0')
918 *d++ = *s++;
919 *d = '\0';
920 return true;

◆ file_spec_path()

bool file_spec_path ( char * fp,
char * fs )

extracts the path component of a file specification

Parameters
fp- path component to return
fs- full file specification
Returns
true if successful
Note
The caller is responsible for ensuring that "fp" has enough space to receive the result.

Definition at line 870 of file futil.c.

871 {
872 if (fs == nullptr || *fs == '\0' || fp == nullptr) {
873 if (fp != nullptr)
874 *fp = '\0';
875 return false;
876 }
877 char *d, *l, *s;
878 s = fp;
879 d = fs;
880 l = nullptr;
881 while (*s != '\0') {
882 if (*s == '/')
883 l = d;
884 *d++ = *s++;
885 }
886 if (l == nullptr)
887 *fp = '\0'; // no slash, so no path
888 else
889 *l = '\0';
890 return true;

◆ format_local_timestamp()

char * format_local_timestamp ( time_t t,
char * buf,
size_t n )

Formats a time_t as an ISO 8601 string in local time.

Parameters
t- time to format
buf- buffer to receive formatted string
n- size of buffer
Returns
pointer to buf
Note
The caller is responsible for ensuring that buf has enough space to hold the resulting string. The ISO 8601 format produced is "YYYY-MM-DDTHH:MM:SS" followed by the local time zone offset (e.g., "+hhmm" or "-hhmm"). This function uses strftime internally, so the actual format may vary based on the implementation of strftime and the locale settings.

Definition at line 303 of file futil.c.

303 {
304 struct tm tmv;
305 localtime_r(&t, &tmv);
306 strftime(buf, n, "%Y-%m-%dT%H:%M:%S", &tmv);
307 return buf;
308}

Referenced by debug_out(), and get_local_timestamp().

Here is the caller graph for this function:

◆ get_argp_doc_by_name()

bool get_argp_doc_by_name ( char * comment,
const struct argp_option * options,
const char * key_name )

Retrieves the documentation string for a given key name from an argp options array.

Parameters
comment- buffer to receive the documentation string
options- array of argp_option structures to search
key_name- the long option name or short option character

Definition at line 176 of file futil.c.

177 {
178 for (size_t i = 0; options[i].name != NULL || options[i].key != 0; i++) {
179 // Skip purely cosmetic header/group entries in argp
180 if (options[i].name == NULL && options[i].doc != NULL &&
181 options[i].key == 0) {
182 continue;
183 }
184
185 // 1. Check against the long option name (e.g., "verbose")
186 if (options[i].name && strcmp(options[i].name, key_name) == 0) {
187 strnz__cpy(comment, options[i].doc, MAXLEN - 1);
188 return true;
189 }
190
191 // 2. Check against the short option key character (e.g., 'v')
192 if (options[i].key > 0 && options[i].key < 127) {
193 char short_str[2] = {(char)options[i].key, '\0'};
194 if (strcmp(short_str, key_name) == 0) {
195 strnz__cpy(comment, options[i].doc, MAXLEN - 1);
196 return true;
197 }
198 }
199 }
200 return false; // Key not found in the argp structure
201}
const char doc[]
Definition lf.c:55

References strnz__cpy().

Referenced by print_argp_doc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_ip_addresses()

char * get_ip_addresses ( char * ip_str,
int maxlen )

Retrieves the IP addresses of the local machine and formats them into a string.

Parameters
ip_str- buffer to receive formatted string of IP addresses
maxlen- size of buffer
Returns
pointer to ip_str containing the formatted IP addresses, or nullptr if an error occurs

This function uses getifaddrs to retrieve a linked list of network interfaces on the local machine. It iterates through the list and checks for interfaces with IPv4 addresses (AF_INET). For each valid interface, it converts the binary IP address to a human-readable string using inet_ntop and appends it to the provided buffer in the format "[interface-name-IP-address]". Multiple interfaces are separated by commas. The caller must ensure that ip_str has enough space to hold the resulting string. If getifaddrs fails, this function returns nullptr and does not modify the buffer.

Definition at line 354 of file futil.c.

354 {
355 char tmp_str[MAXLEN];
356 struct ifaddrs *ifaddr, *ifa;
357 char host[INET_ADDRSTRLEN];
358 bool comma_before = false;
359 // getifaddrs returns a linked list of network interface structures
360 if (getifaddrs(&ifaddr) == -1) {
361 perror("getifaddrs");
362 exit(EXIT_FAILURE);
363 }
364 ip_str[0] = '\0';
365 // Walk through the linked list
366 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
367 if (ifa->ifa_addr == NULL)
368 continue;
369 // Check for IPv4 addresses
370 if (ifa->ifa_addr->sa_family == AF_INET) {
371 struct sockaddr_in *pAddr = (struct sockaddr_in *)ifa->ifa_addr;
372
373 // Convert binary IP to human-readable string
374 inet_ntop(AF_INET, &pAddr->sin_addr, host, INET_ADDRSTRLEN);
375
376 if (comma_before)
377 snprintf(tmp_str, MAXLEN - 1, ",[%s-%s]", ifa->ifa_name, host);
378 else
379 snprintf(tmp_str, MAXLEN - 1, "[%s-%s]", ifa->ifa_name, host);
380 strnz__cat(ip_str, tmp_str, maxlen - 1);
381 comma_before = true;
382 }
383 }
384 freeifaddrs(ifaddr); // Clean up the memory allocated by getifaddrs
385 return ip_str;
386}

References strnz__cat().

Referenced by debug_out().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_local_timestamp()

char * get_local_timestamp ( )

Returns the current local time as an ISO 8601 formatted string.

Returns
pointer to static buffer containing the current local timestamp in ISO 8601 format
Note
The returned string is stored in a static buffer, so it will be overwritten by subsequent calls to this function. The format of the returned string is "YYYY-MM-DDTHH:MM:SS" followed by the local time zone offset (e.g., "+hhmm" or "-hhmm"). This function uses the current system time and formats it using strftime internally, so the actual format may vary based on the implementation of strftime and the locale settings.

Definition at line 314 of file futil.c.

314 {
315 static char buf[32];
316 time_t t = time(NULL);
317 format_local_timestamp(t, buf, sizeof buf);
318 return buf;
319}
char * format_local_timestamp(time_t, char *, size_t)
Formats a time_t as an ISO 8601 string in local time.
Definition futil.c:303

References format_local_timestamp().

Referenced by debug_out().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_user_str()

char * get_user_str ( char * user_str,
size_t maxlen )

Retrieves the current user's name and UID, and formats it into a string.

Parameters
user_str- buffer to receive formatted string
maxlen- size of buffer
Returns
pointer to user_str containing the formatted user information, or nullptr if an error occurs

This function uses getuid to retrieve the current user's UID, then uses getpwuid to get the corresponding passwd structure, which contains the user's name. It formats the user's name and UID into the provided buffer in the format "User: username (uid)\n". The caller must ensure that user_str has enough space to hold the resulting string. If getpwuid fails (e.g., if the UID does not exist), this function returns nullptr and does not modify the buffer.

Definition at line 327 of file futil.c.

327 {
328 uid_t uid = getuid();
329 struct passwd *pw = getpwuid(uid);
330 if (pw == NULL)
331 return nullptr;
332 ssnprintf(user_str, maxlen - 1, "%s (%u)", pw->pw_name, (unsigned int)uid);
333 return user_str;
334}
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition futil.c:420

References ssnprintf().

Referenced by debug_out().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_directory()

bool is_directory ( const char * path)

Checks if the given path is a directory.

Parameters
path- path to check
Returns
0 exists 1 is a directory -1 does not exist

Definition at line 1372 of file futil.c.

1373 {
1374 struct stat statbuf;
1375 if (stat(path, &statbuf) == 0)
1376 if (S_ISDIR(statbuf.st_mode))
1377 return true;
1378 return false;

Referenced by main().

Here is the caller graph for this function:

◆ is_hex_str()

bool is_hex_str ( char * str,
int len )

Validates that a string consists of exactly len hexadecimal digits.

Parameters
str- input string to validate
len- expected number of hexadecimal digits
Returns
true if str is a valid hex string of the specified length, false otherwise

This function checks that the input string contains only hexadecimal characters (0-9, A-F, a-f) and that the total number of hex digits matches the specified length. If the input string is valid, it returns true; otherwise, it returns false. The caller must ensure that the input string is not null and has at least one character before calling this function.

Definition at line 209 of file futil.c.

209 {
210 char *s = str;
211 char *e;
212 if (s == NULL || *s == '\0')
213 return false;
214 e = (s + len + 1);
215 while (s < e && *s != '\0') {
216 if (!isxdigit(*s)) {
217 return false;
218 }
219 s++;
220 }
221 if ((int)(s - str) != len)
222 return false;
223 return true;
224}

◆ is_newer()

bool is_newer ( char * control,
char * fut )

Checks if the file specified by "fut" is newer than the file specified by "control".

Parameters
control- path to the control file
fut- path to the file to compare against the control file
Returns
true if "fut" is newer than "control", false otherwise

This function uses the stat system call to retrieve the modification times of both files. It compares the modification time of "fut" with that of "control" and returns true if "fut" has a more recent modification time. If either file cannot be accessed or if any error occurs during the stat calls, this function returns false. The caller must ensure that both file paths are valid and that the files exist before calling this function.

Definition at line 160 of file futil.c.

160 {
161 // is fut newer than control?
162 struct stat control_st, fut_st;
163 if (!stat(control, &control_st))
164 if (!lstat(fut, &fut_st))
165 if (fut_st.st_mtime > control_st.st_mtime)
166 return true;
167 return false;
168}

◆ is_symlink_to_dir()

bool is_symlink_to_dir ( const char * path)

Checks if the given path is a symbolic link to a directory.

Parameters
path- path to check
Returns
0 exists 1 symbolic link to a directory -1 does not exist or not a symbolic link to a directory

Definition at line 1385 of file futil.c.

1386 {
1387 struct stat link_stat;
1388 struct stat target_stat;
1389
1390 if (lstat(path, &link_stat) == 0)
1391 if (S_ISLNK(link_stat.st_mode))
1392 if (stat(path, &target_stat) == 0)
1393 if (S_ISDIR(target_stat.st_mode))
1394 return true; // symbolic link to a directory
1395 return false;

Referenced by main().

Here is the caller graph for this function:

◆ is_valid_regex()

bool is_valid_regex ( const char * pattern)

Checks if the given regular expression pattern is valid.

Parameters
pattern- regular expression pattern to check
Returns
true if the pattern is valid, false otherwise

Definition at line 1400 of file futil.c.

1401 {
1402 regex_t regex;
1403 int ret = regcomp(&regex, pattern, REG_EXTENDED);
1404 regfree(&regex);
1405 if (ret == 0)
1406 return true;
1407 return false;

Referenced by main().

Here is the caller graph for this function:

◆ iso8601_time()

char * iso8601_time ( char * buf,
int n,
time_t * t,
bool local )

Formats a struct tm as an ISO 8601 string.

Parameters
buf- buffer to receive formatted string
n- size of buffer
t- struct tm to format
local- if true, include local time zone offset; if false, use 'Z' for UTC
Returns
pointer to buf
Note
The caller is responsible for ensuring that buf has enough space to hold the resulting string. The ISO 8601 format produced is "YYYY-MM-DDTHH:MM:SSZ" for UTC or "YYYY-MM-DDTHH:MM:SS±hhmm" for local time. This function uses strftime internally, so the actual format may vary based on the implementation of strftime and the locale settings.

Definition at line 264 of file futil.c.

264 {
265 struct tm *tp = local ? localtime(t) : gmtime(t);
266 if (local) {
267 strftime(buf, n, "%Y-%m-%dT%H:%M:%S%z", tp);
268 } else {
269 strftime(buf, n, "%Y-%m-%dT%H:%M:%SZ", tp);
270 }
271 return buf;
272}

◆ locate_file_in_path()

bool locate_file_in_path ( char * file_spec,
char * file_name )

Locates a file in the system PATH.

Parameters
file_spec- buffer to receive located file specification
file_name- name of file to locate
Returns
true if file is located
Note
file_spec must be large enough to receive the result

Definition at line 1287 of file futil.c.

1288 {
1289 if (file_name == nullptr || *file_name == '\0' || file_spec == nullptr)
1290 return false;
1291 char path[MAXLEN];
1292 char ifn[MAXLEN];
1293 char *p, *fnp, *dir;
1294
1295 canonicalize_file_spec(file_name);
1296 strnz__cpy(ifn, file_name, MAXLEN - 1);
1297 fnp = ifn;
1298 while (*fnp && *fnp != '/')
1299 fnp++;
1300 if (*fnp == '/')
1301 return false;
1302 if ((p = getenv("PATH")) == nullptr)
1303 return false;
1304 strnz__cpy(path, p, MAXLEN - 1);
1305 dir = strtok(path, ":");
1306 while (dir != nullptr) {
1307 strnz__cpy(file_spec, dir, MAXLEN - 1);
1308 strnz__cat(file_spec, "/", MAXLEN - 1);
1309 strnz__cat(file_spec, file_name, MAXLEN - 1);
1310 if (access(file_spec, F_OK) == 0) {
1311 return true;
1312 }
1313 dir = strtok(nullptr, ":");
1314 }
1315 return false;
size_t canonicalize_file_spec(char *)
Removes quotes and trims at first space.
Definition futil.c:1341

References canonicalize_file_spec(), strnz__cat(), and strnz__cpy().

Referenced by init_form_files(), init_pick_files(), and verify_spec_arg().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mk_dir()

bool mk_dir ( char * dir)

If directory doesn't exist, make it.

Parameters
dirdirectory name
Returns
true if directory now exists or false otherwise

Directory does not exist and unable to create

Definition at line 1320 of file futil.c.

1321 {
1322 expand_tilde(dir, MAXLEN - 1);
1323 if (!verify_dir(dir, S_WCOK | S_QUIET)) {
1324 if (!mkdir(dir, 0755)) {
1326 ssnprintf(em0, MAXLEN - 1, "%s, line: %d", __FILE__, __LINE__ - 2);
1327 strnz__cpy(em1, "mkdir ", MAXLEN - 1);
1328 strnz__cat(em1, dir, MAXLEN - 1);
1329 strnz__cat(em1, " failed", MAXLEN - 1);
1330 strerror_r(errno, em2, MAXLEN - 1);
1331 display_error(em0, em1, em2, nullptr);
1332 return false;
1333 }
1334 return true;
1335 }
1336 return true;
char em1[MAXLEN]
Definition dwin.c:176
char em0[MAXLEN]
Definition dwin.c:175
#define S_QUIET
Definition cm.h:286
#define S_WCOK
Definition cm.h:285
char em2[MAXLEN]
Definition dwin.c:177
int display_error(char *, char *, char *, char *)
Display an error message window or print to stderr.
Definition dwin.c:1467
bool expand_tilde(char *str, int path_maxlen)
Replaces "~/" in string with the user's home directory.
Definition futil.c:970
bool verify_dir(char *, int)
Verifies that the directory specified by "spec" exists and is accessible with the permissions specifi...
Definition futil.c:1189

References display_error(), em0, em1, em2, expand_tilde(), ssnprintf(), strnz__cat(), strnz__cpy(), and verify_dir().

Referenced by enter_file_spec().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ normalize_file_spec()

bool normalize_file_spec ( char * fs)

replace backslashes with forward lashes

Parameters
fs- file specification to normalize
Returns
true if successful, false if fs is nullptr or empty

Definition at line 853 of file futil.c.

854 {
855 if (fs == nullptr || *fs == '\0')
856 return false;
857 while (*fs != '\0') {
858 if (*fs == '\\')
859 *fs = '/';
860 fs++;
861 }
862 return true;

◆ open_cmenu_log()

void open_cmenu_log ( )

Open new C-Menu log file.

Definition at line 1667 of file futil.c.

1668 {
1669 char ttyname[MAXLEN];
1670 char cmenu_user[MAXLEN];
1671 char *p;
1672 cmenu_log_fd = open("/tmp/cmenu.log", O_WRONLY | O_CREAT | O_TRUNC,
1673 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
1674 p = getenv("USER");
1675 strnz__cpy(cmenu_user, p, MAXLEN - 1);
1676 if (ttyname_r(STDERR_FILENO, ttyname, sizeof(ttyname)) == 0)
1677 strnz__cpy(em0, ttyname, MAXLEN - 1);
1678 ssnprintf(em0, MAXLEN - 1, "C-Menu started by user '%s' on terminal '%s'\n",
1679 cmenu_user, ttyname);
int cmenu_log_fd
Definition futil.c:54
void write_cmenu_log(char *)
Write message to C-Menu log file with timestamp.
Definition futil.c:1685

References cmenu_log_fd, em0, ssnprintf(), strnz__cpy(), and write_cmenu_log().

Here is the call graph for this function:

◆ parse_local_timestamp()

bool parse_local_timestamp ( const char * s,
time_t * out )

Parses an ISO 8601 timestamp string in local time and converts it to time_t.

Parameters
s- ISO 8601 timestamp string to parse (e.g., "2024-06-01T12:34:56")
out- pointer to time_t variable to receive the result
Returns
true if parsing and conversion were successful, false otherwise

This function expects the input string to be in the format "YYYY-MM-DDTHH:MM:SS" representing local time. It uses strptime to parse the string into a struct tm, then uses mktime to convert it to time_t. The caller must ensure that the input string is properly formatted and represents a valid date and time. If the input string is invalid or if any error occurs during parsing or conversion, this function returns false and does not modify the output variable.

Definition at line 280 of file futil.c.

280 {
281 struct tm tmv;
282 memset(&tmv, 0, sizeof tmv);
283 tmv.tm_isdst = -1;
284
285 if (strptime(s, "%Y-%m-%dT%H:%M:%S", &tmv) == NULL)
286 return false;
287
288 time_t t = mktime(&tmv);
289 if (t == (time_t)-1)
290 return false;
291
292 *out = t;
293 return true;
294}

◆ rep_substring()

char * rep_substring ( const char * org_s,
const char * tgt_s,
const char * rep_s )

Replace all occurrences of "tgt_s" in "org_s" with "rep_s".

Parameters
org_s- original string
tgt_s- target substring to replace
rep_s- replacement substring
Returns
A pointer to the newly allocated string with replacements or a copy of the replacement string if original string is the same as target string This is a special case that allows for replacing the entire original string. If any parameter is nullptr, the function returns nullptr. If "tgt_s" is not found in "org_s", the function returns a copy of "org_s". If target substring is not found the function returns a copy of the original string.
Note
allocates memory for the return value, so the caller is responsible for freeing this memory when it is no longer needed to avoid memory leaks. Does not modify the original string "org_s".
Assumes that "tgt_s" and "rep_s" are null-terminated strings. If they are not, the behavior is undefined.
Does not perform any bounds checking on the input strings, so it is the caller's responsibility to ensure that they are valid and that the resulting string does not exceed available memory.
Uses the standard library functions strlen, strstr, malloc, and strcpy, which may have their own limitations and behaviors that the caller should be aware of.
Does not handle overlapping occurrences of "tgt_s" in "org_s". If "tgt_s" can overlap with itself in "org_s", the behavior may be unexpected. The caller should ensure that "tgt_s" does not contain overlapping patterns to avoid this issue.
Does not handle cases where "tgt_s" is a substring of "rep_s", which could lead to unintended consequences if "tgt_s" appears in "rep_s". The caller should ensure that "tgt_s" and "rep_s" are distinct to avoid this issue.

Definition at line 1440 of file futil.c.

1441 {
1442 if (org_s == nullptr || tgt_s == nullptr || rep_s == nullptr)
1443 return nullptr;
1444 if (*org_s == '\0' || *tgt_s == '\0' || *rep_s == '\0')
1445 return nullptr;
1446 if (strstr(org_s, tgt_s) == nullptr)
1447 return strdup(org_s);
1448 if (strstr(rep_s, tgt_s) != nullptr)
1449 return nullptr;
1450 if (tgt_s == rep_s || tgt_s == org_s || rep_s == org_s)
1451 return strdup(org_s);
1452 if (strcmp(org_s, tgt_s) == 0)
1453 return strdup(rep_s);
1454 char *out_s, *ip, *tmp;
1455 int tgt_l = strlen(tgt_s);
1456 int rep_l = strlen(rep_s);
1457 int head_l;
1458 int n = 0;
1459 ip = (char *)org_s;
1460 while ((tmp = strstr(ip, tgt_s)) != nullptr) {
1461 n++;
1462 ip = tmp + tgt_l;
1463 }
1464 out_s = malloc(strlen(org_s) + (rep_l - tgt_l) * n + 1);
1465 if (!out_s) {
1466 return nullptr;
1467 }
1468 tmp = out_s;
1469 ip = (char *)org_s;
1470 while (n--) {
1471 char *p = strstr(ip, tgt_s);
1472 head_l = p - ip;
1473 strnz__cpy(tmp, ip, head_l);
1474 tmp += head_l;
1475 strnz__cpy(tmp, rep_s, MAXLEN - 1);
1476 tmp += rep_l;
1477 ip += head_l + tgt_l;
1478 }
1479 strnz__cpy(tmp, ip, MAXLEN - 1);
1480 return out_s;

References strnz__cpy().

Referenced by exec_objects(), expand_tilde(), and form_exec_receiver().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ssnprintf()

size_t ssnprintf ( char * buf,
size_t buf_size,
const char * format,
... )

ssnprintf was designed to be a safer alternative to snprintf.

It ensures that the buffer is not overflowed by taking the buffer size as a parameter and using vsnprintf internally. It also returns the number of characters that would have been written if enough space had been available, allowing the caller to detect truncation. This function is particularly useful in situations where the formatted string may exceed the buffer size, as it prevents buffer overflows and provides a way to handle such cases gracefully.

Parameters
buf- buffer to receive formatted string
buf_size- size of buffer
format- printf-style format string
...- arguments
Returns
number of characters that would have been written if enough space had been available

Definition at line 420 of file futil.c.

420 {
421 size_t n;
422 va_list args;
423
424 va_start(args, format);
425 n = vsnprintf(buf, buf_size, format, args);
426 va_end(args);
427
428 return n;
429}

Referenced by action_disposition(), answer_yn(), check_panels(), compile_chyron(), debug_out(), display_error(), display_line(), enter_file_spec(), fork_exec(), form_desc_error(), form_parse_desc(), form_process(), form_write(), get_clr_pair(), get_user_str(), handle_signal(), init_view_boxwin(), init_view_full_screen(), lp(), mapp_initialization(), menu_engine(), mk_dir(), new_init(), new_pick(), new_view(), open_cmenu_log(), open_pick_win(), pad_refresh(), parse_menu_description(), Perror(), picker(), search(), set_chyron_key(), set_chyron_key_cp(), signal_handler(), stdio_fdnames(), stdio_names(), verify_dir(), verify_file(), view_cmd_processor(), view_init_input(), wait_continue(), wait_mk_win(), waitpid_with_timeout(), write_config(), and write_view_buffer().

Here is the caller graph for this function:

◆ str_subc()

bool str_subc ( char * d,
char * s,
char ReplaceChr,
char * Withstr,
int l )

Replaces "ReplaceChr" in "s" with "Withstr" in "d" won't copy more than "l" bytes to "d" Replaces all occurrences of a character in a string with another string, copying the result to a destination buffer.

Parameters
d- destination string
s- source string
ReplaceChr- character to replace
Withstr- string to insert
l- maximum length to copy
Returns
true if successful, false if any parameter is invalid

This function ensures that the total length of the resulting string does not exceed the specified limit, and that the result is null-terminated. This function is useful for simple string substitutions where you want to replace a single character with a longer string, such as replacing spaces with underscores or tabs with spaces.

Note
The caller must ensure that "d" has enough space to receive the result, and that "l" is sufficient to hold the result. This function does not perform any bounds checking on "d" or "Withstr", so it is the caller's responsibility to ensure that they are valid and that "l" is appropriate for the operation.

Definition at line 690 of file futil.c.

690 {
691 char *e;
692 if (s == nullptr || d == nullptr || Withstr == nullptr || l == 0) {
693 if (d != nullptr && l > 0)
694 *d = '\0';
695 return false;
696 }
697 e = d + l;
698 while (*s != '\0' && d < e) {
699 if (*s == ReplaceChr) {
700 while (*Withstr != '\0' && d < e)
701 *d++ = *Withstr++;
702 s++;
703 } else
704 *d++ = *s++;
705 }
706 *d = '\0';
707 return true;
708}

Referenced by view_cmd_processor().

Here is the caller graph for this function:

◆ str_to_args()

int str_to_args ( char ** argv,
char * arg_str,
int max_args )

Converts a string into an array of argument strings.

Parameters
argv- array of pointers to arguments
arg_str- string containing arguments
max_args- maximum number of arguments to parse
Returns
argc, a count of allocated vectors in argv

Handles quoted strings and escaped quotes, preserving text inside quotes as individual arguments. It has been in service for many years without problems.

Note
The caller is responsible for deallocating the strings in argv.

Definition at line 440 of file futil.c.

440 {
441 if (arg_str == nullptr || *arg_str == '\0')
442 return 0;
443 int argc = 0;
444 char *p = arg_str;
445 char tmp_str[MAXLEN];
446 int in_quotes = 0;
447 char *d = tmp_str;
448
449 while (*p != '\0' && argc < max_args) {
450 while (isspace((unsigned char)*p))
451 p++;
452 if (*p == '\0')
453 break;
454 if (*p == '"') {
455 in_quotes = 1;
456 p++;
457 }
458 while (*p != '\0') {
459 if (in_quotes) {
460 if (*p == '\\' && *(p + 1) == '"') {
461 *d++ = '"';
462 p += 2;
463 } else if (*p == '"') {
464 *d++ = '\0';
465 p++;
466 in_quotes = 0;
467 break;
468 } else
469 *d++ = *p++;
470 } else {
471 if (isspace((unsigned char)*p)) {
472 *d++ = '\0';
473 p++;
474 break;
475 } else
476 *d++ = *p++;
477 }
478 }
479 *d = '\0';
480 d = tmp_str;
481 argv[argc++] = strdup(tmp_str);
482 }
483 argv[argc] = nullptr;
484 return argc;
485}

Referenced by enter_file_spec(), exec_objects(), form_exec_receiver(), form_process(), init_pick(), menu_cmd_processor(), and view_init_input().

Here is the caller graph for this function:

◆ str_to_double()

double str_to_double ( char * s)

converts string to double

Parameters
s- string to convert
Returns
converted double value, or 0.0 if s is nullptr, empty, or invalid
Note
The caller must ensure that the string is a valid representation of a double before calling this function.

Definition at line 929 of file futil.c.

930 {
931 char *e;
932 double d;
933
934 if (!s || !*s)
935 return false;
936 d = strtod(s, &e);
937 return d;

Referenced by process_config_file().

Here is the caller graph for this function:

◆ str_to_lower()

bool str_to_lower ( char * s)

Converts a string to lowercase.

Parameters
s- string to convert
Returns
true if successful, false if s is nullptr or empty

Definition at line 508 of file futil.c.

508 {
509 if (s == nullptr || *s == '\0')
510 return false;
511 while (*s != '\0') {
512 if (*s >= 'A' && *s <= 'Z')
513 *s = *s + 'a' - 'A';
514 s++;
515 }
516 return true;
517}

Referenced by clr_name_to_idx(), and form_parse_desc().

Here is the caller graph for this function:

◆ str_to_upper()

bool str_to_upper ( char * s)

Converts a string to uppercase.

Parameters
s- string to convert
Returns
true if successful, false if s is nullptr or empty

Definition at line 522 of file futil.c.

522 {
523 if (s == nullptr || *s == '\0')
524 return false;
525 while (*s != '\0') {
526 if (*s >= 'a' && *s <= 'z')
527 *s = *s + 'A' - 'a';
528 s++;
529 }
530 return true;
531}

◆ strip_ansi()

size_t strip_ansi ( char * d,
char * s )

Strips ANSI SGR escape sequences (ending in 'm') from string s to d.

Parameters
dDestination string
sSource string
Returns
Length of stripped string
char dest[1024];
char src[] = "\033[31mThis is red text\033[0m
size_t len = strip_ansi(dest, src);
Result: dest = "This is red text", len = 17
@example stripansi.c

Only handles SGR sequences ending in 'm' or 'K' Skips non-ASCII characters The caller must ensure that d has enough space to hold the stripped string This function does not allocate memory; it assumes d is pre-allocated This function processes the entire string until the null terminator This function does not modify the source string s

Definition at line 829 of file futil.c.

830 {
831 size_t l = 0;
832 while (*s) {
833 if (*s == '\033') {
834 while (*s && *s != 'm' && *s != 'K')
835 s++;
836 if (*s == 'm' || *s == 'K')
837 s++;
838 continue;
839 } else {
840 if ((unsigned char)*s <= 127) {
841 *d++ = *s++;
842 l++;
843 } else
844 s++;
845 }
846 }
847 *d = '\0';
848 return l;

Referenced by main(), and write_view_buffer().

Here is the caller graph for this function:

◆ strip_quotes()

bool strip_quotes ( char * s)

removes leading and trailing double quotes if present

Parameters
s- string to strip quotes from
Returns
true if successful, false if s is nullptr or empty

If the string has a leading double quote and a trailing double quote, this function removes them in place. If the string does not have both leading and trailing double quotes, it is left unchanged. The function returns true if the operation was successful (i.e., if the string was modified or if it was valid), and false if the input string was null or empty.

Definition at line 718 of file futil.c.

718 {
719 if (s == nullptr)
720 return false;
721 int l = strlen(s);
722 if (l > 1 && s[l - 1] == '\"') {
723 memmove(s, s + 1, l - 2);
724 s[l - 2] = '\0';
725 }
726 return true;
727}

Referenced by init_form_files(), and init_view_files().

Here is the caller graph for this function:

◆ stripz_quotes()

bool stripz_quotes ( char * s)

removes leading and trailing double quotes if present

Parameters
s- string to strip quotes from
Returns
true if quotes were removed

Same as STRIP_QUOTES but returns true if quotes were removed

Definition at line 733 of file futil.c.

733 {
734 if (s == nullptr || strlen(s) < 2)
735 return false;
736 int l = strlen(s);
737 if (l > 1 && s[0] == '\"' && s[l - 1] == '\"') {
738 memmove(s, s + 1, l - 2);
739 s[l - 2] = '\0';
740 return true;
741 }
742 return false;
743}

Referenced by verify_spec_arg().

Here is the caller graph for this function:

◆ strnlf()

size_t strnlf ( char * s,
size_t max_len )

terminates string with line feed

Parameters
sstring to terminate
max_lenmaximum length to scan
Returns
length of resulting string

Definition at line 633 of file futil.c.

633 {
634 char *e;
635 size_t len = 0;
636 if (s == nullptr || *s == '\0' || max_len == 0)
637 return 0;
638 e = s + max_len;
639 while (*s != '\0' && *s != '\n' && *s != '\r' && s < e) {
640 s++;
641 len++;
642 }
643 *s++ = '\n';
644 len++;
645 *s = '\0';
646 return (len);
647}

Referenced by write_view_buffer().

Here is the caller graph for this function:

◆ strnz()

size_t strnz ( char * s,
size_t max_len )

terminates string at New Line, Carriage Return, or max_len

Parameters
sstring to terminate
max_len- maximum length to scan
Returns
length of resulting string

The use case is to ensure that strings read from files or user input do not contain embedded newlines or carriage returns.

Definition at line 615 of file futil.c.

615 {
616 char *e;
617 size_t len = 0;
618 if (s == nullptr || *s == '\0' || max_len == 0)
619 return 0;
620 e = s + max_len;
621 while (*s != '\0' && *s != '\n' && *s != '\r' && s < e) {
622 s++;
623 len++;
624 }
625 *s = '\0';
626 return (len);
627}

Referenced by answer_yn(), border_hsplit_text(), display_error(), display_form(), enter_file_spec(), form_display_fields(), form_fmt_field(), message_win(), and Perror().

Here is the caller graph for this function:

◆ strnz__cat()

size_t strnz__cat ( char * d,
const char * s,
size_t max_len )

safer alternative to strncat

Parameters
d- destination string
s- source string
max_len- maximum length to copy
Returns
length of resulting string

Append string s to d, ensuring that the total length of d does not exceed max_len, and that the resulting string is null-terminated. It also treats newline and carriage return characters as string terminators, preventing them from being included in the result. This is particularly useful when concatenating user input or file data, where embedded newlines could cause issues.

Definition at line 573 of file futil.c.

573 {
574 char *e;
575 size_t len = 0;
576 if (s == nullptr || d == nullptr || max_len == 0) {
577 if (d != nullptr && max_len > 0)
578 *d = '\0';
579 return 0;
580 }
581 e = d + max_len;
582 while (*d != '\0' && *d != '\n' && *d != '\r' && d < e) {
583 d++;
584 len++;
585 }
586 while (*s != '\0' && *s != '\n' && *s != '\r' && d < e) {
587 *d++ = *s++;
588 len++;
589 }
590 *d = '\0';
591 return len;
592}

Referenced by build_prompt(), derive_file_spec(), display_form(), display_pick_help(), enter_file_spec(), exec_objects(), expand_tilde(), file_spec_parts(), form_engine(), form_exec_cmd(), form_exec_receiver(), form_parse_desc(), form_process(), form_read_data(), form_write(), get_ip_addresses(), init_form(), init_menu_files(), init_pick(), init_view_files(), locate_file_in_path(), mapp_initialization(), menu_cmd_processor(), mk_dir(), new_pick_view(), new_view_file(), open_curses(), output_objects(), parse_menu_description(), picker(), popup_ckeys(), search(), stdio_fdnames(), stdio_names(), verify_spec_arg(), view_cmd_processor(), view_display_help(), view_init_input(), whence(), write_cmenu_log(), write_config(), and write_view_buffer().

Here is the caller graph for this function:

◆ strnz__cpy()

size_t strnz__cpy ( char * d,
const char * s,
size_t max_len )

safer alternative to strncpy

copies string s to d, ensuring that the total length of d does not exceed max_len, and that the resulting string is null-terminated. It also treats newline and carriage return characters as string terminators, preventing them from being included in the result. This is particularly useful when copying user input or file data, where embedded newlines could cause issues.

Parameters
d- destination string
s- source string
max_len- maximum length to copy
Returns
length of resulting string

Definition at line 544 of file futil.c.

544 {
545 char *e;
546 size_t len = 0;
547 if (s == nullptr || d == nullptr || max_len == 0) {
548 if (d != nullptr && max_len > 0)
549 *d = '\0';
550 return 0;
551 }
552 e = d + max_len;
553 while (*s != '\0' && *s != '\n' && *s != '\r' && d < e) {
554 *d++ = *s++;
555 len++;
556 }
557 *d = '\0';
558 return len;
559}

Referenced by answer_yn(), build_prompt(), canonicalize_file_spec(), derive_file_spec(), dir_name(), display_error(), display_form(), display_pick_help(), display_prompt(), enter_file_spec(), exec_objects(), expand_tilde(), file_spec_parts(), form_desc_error(), form_engine(), form_exec_cmd(), form_exec_receiver(), form_fmt_field(), form_parse_desc(), form_process(), form_read_data(), form_write(), get_argp_doc_by_name(), get_cmd_arg(), handle_signal(), init_form(), init_form_files(), init_menu_files(), init_pick(), init_pick_files(), init_view_files(), locate_file_in_path(), main(), mapp_initialization(), menu_cmd_processor(), mk_dir(), new_form(), new_pick_view(), new_view_file(), open_cmenu_log(), open_curses(), output_objects(), parse_menu_description(), Perror(), picker(), popup_ckeys(), process_config_file(), process_config_files(), rep_substring(), save_object(), search(), stdio_fdnames(), stdio_names(), verify_dir(), verify_file(), verify_spec_arg(), view_cmd_processor(), view_display_help(), view_file(), view_init_input(), whence(), write_cmenu_log(), write_config(), and write_view_buffer().

Here is the caller graph for this function:

◆ strnz_dup()

char * strnz_dup ( char * s,
size_t l )

Allocates memory for and duplicates string s up to length l or until line feed or carriage return.

Parameters
s- string to duplicate
l- maximum length to copy
Returns
pointer to allocated memory

Definition at line 654 of file futil.c.

654 {
655 char *p, *ms, *e;
656 size_t m;
657 if (s == nullptr || *s == '\0' || l == 0)
658 return nullptr;
659 for (p = s, m = 1; *p != '\0'; p++, m++)
660 ;
661 ms = p = (char *)malloc(m);
662 if (ms != nullptr) {
663 e = ms + l;
664 while (*s != '\0' && *s != '\n' && *s != '\r' && p < e)
665 *p++ = *s++;
666 *p = '\0';
667 }
668 return ms;
669}

Referenced by new_view().

Here is the caller graph for this function:

◆ strz()

size_t strz ( char * s)

Terminates string at new line or carriage return.

Parameters
sstring to terminate

Definition at line 597 of file futil.c.

597 {
598 size_t l = 0;
599 if (s == nullptr || *s == '\0')
600 return 0;
601 while (*s != '\0' && *s != '\n' && *s != '\r') {
602 s++;
603 l++;
604 }
605 *s = '\0';
606 return l;
607}

◆ trim()

size_t trim ( char * s)

Trims leading and trailing spaces from string s in place.

Parameters
s- string to trim
Returns
length of trimmed string

Definition at line 391 of file futil.c.

391 {
392 if (s == nullptr || *s == '\0')
393 return 0;
394 char *p = s;
395 char *d = s;
396 while (*p == ' ')
397 p++;
398 while (*p != '\0')
399 *d++ = *p++;
400 while (*(d - 1) == ' ' && d > s)
401 d--;
402 *d = '\0';
403 return (size_t)(d - s);
404}

Referenced by form_fmt_field(), form_parse_desc(), left_justify(), menu_cmd_processor(), parse_menu_description(), and right_justify().

Here is the caller graph for this function:

◆ trim_ext()

bool trim_ext ( char * buf,
char * filename )

trims the file extension from "filename" and copies the result to "buf"

Parameters
buf- buffer to receive result
filename- filename to trim
Note
The caller is responsible for ensuring that "buf" has enough space to receive the result.

Definition at line 1016 of file futil.c.

1017 {
1018 if (!filename || !*filename || !buf)
1019 return false;
1020 char *s = filename;
1021 char *d = buf;
1022 *d = '\0';
1023 while (*s)
1024 s++;
1025 while (filename < --s) {
1026 if (*s == '.') {
1027 break;
1028 }
1029 }
1030 if (*s != '.') {
1031 while (*filename)
1032 *d++ = *filename++;
1033 } else {
1034 while (filename < s) {
1035 *d++ = *filename++;
1036 }
1037 }
1038 *d = '\0';
1039 if (d == buf)
1040 return false;
1041 return true;

◆ trim_path()

bool trim_path ( char * dir)

Trims trailing spaces and slashes from directory path in place.

Parameters
dir- directory path to trim
Returns
true if successful

Definition at line 988 of file futil.c.

989 {
990 if (!dir)
991 return false;
992 char *p;
993
994 if (!dir || !*dir)
995 return false;
996 p = dir;
997 while (*p++ != '\0') {
998 if (*p == ' ' || *p == '\t' || *p == '\n') {
999 *p = '\0';
1000 break;
1001 }
1002 }
1003 --p;
1004 while (--p > dir && *p == '/') {
1005 if (*(p - 1) != '~')
1006 *p = '\0';
1007 }
1008 return true;

Referenced by derive_file_spec().

Here is the caller graph for this function:

◆ ui_rect_set()

void ui_rect_set ( UiRect * r,
int y,
int x,
int h,
int w )

Set the properties of a UiRect structure.

ui_rect_set

Parameters
rPointer to the UiRect structure to set
yY-coordinate (row) of the rectangle's top-left corner
xX-coordinate (column) of the rectangle's top-left corner
hHeight (number of rows) of the rectangle
wWidth (number of columns) of the rectangle

This function initializes the fields of a UiRect structure with the specified values for position and size. It is used to define rectangular areas in a user interface.

Definition at line 908 of file dwin.c.

908 {
909 r->y = y;
910 r->x = x;
911 r->rows = h;
912 r->cols = w;
913}
int cols
Definition ui_backend.h:200
int rows
Definition ui_backend.h:199

References UiRect::cols, UiRect::rows, UiRect::x, and UiRect::y.

◆ unstr_hex_clr()

bool unstr_hex_clr ( char * dst,
char * str )

Validates that a string is a hex color code in the format "#RRGGBB".

Parameters
dst- buffer to receive validated hex color string
str- input string to validate
Returns
true if str is a valid hex color code, false otherwise

This function checks that the input string starts with a '#' character, followed by exactly six hexadecimal digits (0-9, A-F, a-f). If the input string is valid, it copies the hex color code into the provided destination buffer. The caller must ensure that dst has enough space to hold the resulting string (at least 8 characters including the null terminator). If the input string is invalid (e.g., does not start with '#', contains non-hex characters, or does not have exactly six hex digits), this function returns false and does not modify the destination buffer.

Definition at line 232 of file futil.c.

232 {
233 char *s = str;
234 char *e;
235 char *d;
236 if (s == NULL || *s == '\0')
237 return false;
238 if (*s != '#')
239 return false;
240 d = dst;
241 *d++ = *s++;
242 e = (s + 6);
243 while (s < e && *s != '\0') {
244 if (!isxdigit(*s)) {
245 return false;
246 }
247 *d++ = *s++;
248 }
249 *d = '\0';
250 if ((int)(s - str) != 7)
251 return false;
252 return true;
253}

Referenced by process_config_file().

Here is the caller graph for this function:

◆ verify_dir()

bool verify_dir ( char * spec,
int imode )

Verifies that the directory specified by "spec" exists and is accessible with the permissions specified by "imode".

Parameters
spec- directory specification
imode- access mode F_OK - existence R_OK - read W_OK - Write X_OK - Execute S_WCOK - Write or Create S_QUIET - Suppress Error Messages
Returns
true if successful

S_WCOK and S_QUIET are stripped before calling faccessat

Definition at line 1189 of file futil.c.

1190 {
1191 if (spec == nullptr || *spec == '\0')
1192 return false;
1193 expand_tilde(spec, MAXLEN);
1194 struct stat sb;
1195 errno = 0;
1196 src_line = 0;
1197 int mode = imode & ~(S_WCOK | S_QUIET);
1198 if (faccessat(AT_FDCWD, spec, mode, AT_EACCESS) != 0) {
1199 src_line = __LINE__ - 2;
1200 src_name = __FILE__;
1201 strnz__cpy(fn, "faccessat", MAXLEN - 1);
1202 } else {
1203 if (fstatat(AT_FDCWD, spec, &sb, 0) != 0) {
1204 src_line = __LINE__ - 1;
1205 src_name = __FILE__;
1206 strnz__cpy(fn, "fstatat", MAXLEN - 1);
1207 } else {
1208 if ((sb.st_mode & S_IFMT) != S_IFDIR) {
1209 src_line = __LINE__ - 1;
1210 src_name = __FILE__;
1211 strnz__cpy(fn, "verify_file", MAXLEN - 1);
1212 strnz__cpy(em2, "Not a regular file.", MAXLEN - 1);
1213 }
1214 }
1215 }
1216 if (src_line != 0) {
1217 if (!(mode & S_QUIET)) {
1218 ssnprintf(em0, MAXLEN - 1, "%s failed in %s at line %d", fn,
1220 strnz__cpy(em1, spec, MAXLEN - 1);
1221 strnz__cpy(em3, "Check the file", MAXLEN - 1);
1223 }
1224 return false;
1225 }
1226 return true;
int src_line
Definition dwin.c:172
char * src_name
Definition dwin.c:173
char em3[MAXLEN]
Definition dwin.c:178
char fn[MAXLEN]
Definition dwin.c:174

References display_error(), em0, em1, em2, em3, expand_tilde(), fn, src_line, src_name, ssnprintf(), and strnz__cpy().

Referenced by mapp_initialization(), mk_dir(), and verify_spec_arg().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ verify_file()

bool verify_file ( char * in_spec,
int imode )

Verifies that the file specified by "in_spec" exists and is accessible with the permissions specified by "imode".

Parameters
in_spec- directory specification
imode- access mode F_OK - existence R_OK - read W_OK - Write X_OK - Execute S_WCOK - Write or Create S_QUIET - Suppress Error Messages
Returns
true if successful

S_WCOK and S_QUIET are stripped before calling faccessat

Definition at line 1240 of file futil.c.

1241 {
1242 if (in_spec == nullptr || *in_spec == '\0')
1243 return false;
1244 struct stat sb;
1245 char spec[MAXLEN];
1246 strnz__cpy(spec, in_spec, MAXLEN - 1);
1247 int mode = imode & ~(S_WCOK | S_QUIET);
1248 errno = 0;
1249 src_line = 0;
1251 expand_tilde(spec, MAXLEN);
1252 if ((faccessat(AT_FDCWD, spec, mode, AT_EACCESS)) != 0) {
1253 src_line = __LINE__ - 1;
1254 src_name = __FILE__;
1255 strnz__cpy(fn, "faccessat", MAXLEN - 1);
1256 } else {
1257 if ((fstatat(AT_FDCWD, spec, &sb, 0)) != 0) {
1258 src_line = __LINE__ - 1;
1259 src_name = __FILE__;
1260 strnz__cpy(fn, "fstatat", MAXLEN - 1);
1261 } else {
1262 if ((sb.st_mode & S_IFMT) != S_IFREG) {
1263 src_line = __LINE__ - 1;
1264 src_name = __FILE__;
1265 strnz__cpy(fn, "verify_file", MAXLEN - 1);
1266 strnz__cpy(em2, "Not a regular file.", MAXLEN - 1);
1267 }
1268 }
1269 }
1270 if (src_line != 0) {
1271 if (imode & S_QUIET)
1272 return false;
1273 ssnprintf(em0, MAXLEN - 1, "%s failed in %s at line %d", fn, src_name,
1274 src_line);
1275 strnz__cpy(em1, spec, MAXLEN - 1);
1276 strnz__cpy(em3, "Check the file", MAXLEN - 1);
1278 return false;
1279 }
1280 return true;

References canonicalize_file_spec(), display_error(), em0, em1, em2, em3, expand_tilde(), fn, src_line, src_name, ssnprintf(), and strnz__cpy().

Referenced by verify_spec_arg().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ wccp_to_str()

int wccp_to_str ( wchar_t cp,
uint8_t * buffer )

Converts a Unicode code point to a UTF-8 encoded string.

Parameters
cp- Unicode code point to convert
buffer- buffer to receive UTF-8 encoded string (must be at least 4 bytes)
Returns
number of bytes written to buffer, or 0 if cp is invalid

This function encodes the given Unicode code point into its UTF-8 representation and stores it in the provided buffer. The caller must ensure that the buffer has enough space to hold the resulting UTF-8 string (up to 4 bytes for code points up to U+10FFFF). If the code point is invalid (e.g., greater than U+10FFFF), this function returns 0 and does not modify the buffer.

Definition at line 871 of file dwin.c.

871 {
872 if (cp <= 0x7F) {
873 // 1-byte sequence: 0xxxxxxx
874 buffer[0] = (uint8_t)cp;
875 return 1;
876 } else if (cp <= 0x7FF) {
877 // 2-byte sequence: 110xxxxx 10xxxxxx
878 buffer[0] = (uint8_t)(0xC0 | ((cp >> 6) & 0x1F));
879 buffer[1] = (uint8_t)(0x80 | (cp & 0x3F));
880 return 2;
881 } else if (cp <= 0xFFFF) {
882 // 3-byte sequence: 1110xxxx 10xxxxxx 10xxxxxx
883 buffer[0] = (uint8_t)(0xE0 | ((cp >> 12) & 0x0F));
884 buffer[1] = (uint8_t)(0x80 | ((cp >> 6) & 0x3F));
885 buffer[2] = (uint8_t)(0x80 | (cp & 0x3F));
886 return 3;
887 } else if (cp <= 0x10FFFF) {
888 // 4-byte sequence: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
889 buffer[0] = (uint8_t)(0xF0 | ((cp >> 18) & 0x07));
890 buffer[1] = (uint8_t)(0x80 | ((cp >> 12) & 0x3F));
891 buffer[2] = (uint8_t)(0x80 | ((cp >> 6) & 0x3F));
892 buffer[3] = (uint8_t)(0x80 | (cp & 0x3F));
893 return 4;
894 }
895 return 0; // Invalid Unicode code point
896}

◆ write_cmenu_log()

void write_cmenu_log ( char * msg)

Write message to C-Menu log file with timestamp.

Parameters
msg- string to write to log file

Definition at line 1685 of file futil.c.

1686 {
1687 char time_buf[100];
1688 time_t now = time(NULL);
1689 struct tm *t = localtime(&now);
1690 strftime(time_buf, sizeof(time_buf), "%Y-%m-%dT%H:%M:%S%z", t);
1691 strnz__cpy(em1, time_buf, MAXLEN - 1);
1692 strnz__cat(em1, " ", MAXLEN - 1);
1693 strnz__cat(em1, msg, MAXLEN - 1);
1694 write(cmenu_log_fd, em1, strlen(em1));
1695 write(cmenu_log_fd, "\n", 1);
1696 return;

References cmenu_log_fd, em1, strnz__cat(), and strnz__cpy().

Referenced by open_cmenu_log().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ write_cmenu_log_nt()

void write_cmenu_log_nt ( char * msg)

Write message to C-Menu log file without timestamp.

Parameters
msg- string to write to log file

Definition at line 1701 of file futil.c.

1702 {
1703 write(cmenu_log_fd, msg, strlen(msg));
1704 write(cmenu_log_fd, "\n", 1);
1705 return;

References cmenu_log_fd.