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 (uint 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, uint 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, uint 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, uint 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, uint 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, uint 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, uint 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.
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, uint imode)
 Verifies that the directory specified by "spec" exists and is accessible with the permissions specified by "imode".
bool verify_file (char *in_spec, uint imode)
 Verifies that the file specified by "in_spec" exists and is accessible with the permissions specified by "imode".
void write_cmenu_log (char *msg)
 Write message to C-Menu log file without timestamp.
void write_cmenu_log_ts (char *msg)
 Write message to C-Menu log file with 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 786 of file futil.c.

786 {
787 char *endptr;
788 unsigned long value = (unsigned long)strtoull(str, &endptr, 10);
789 if (endptr == str)
790 return 0;
791 switch (tolower(*endptr)) {
792 case 'g':
793 return value * 1024ULL * 1024ULL * 1024ULL;
794 case 'm':
795 return value * 1024ULL * 1024ULL;
796 case 'k':
797 return value * 1024ULL;
798 default:
799 return value;
800 }
801}

◆ 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 762 of file futil.c.

762 {
763 int rc = -1;
764 *a_toi_error = false;
765 errno = 0;
766 if (s && *s != 0)
767 rc = (uint)strtol(s, nullptr, 10);
768 if (rc < 0 || errno) {
769 rc = -1;
770 *a_toi_error = true;
771 }
772 return rc;
773}

Referenced by assign_chyron_win(), parse_ansi(), and 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 1106 of file futil.c.

1107 {
1108 if (!path || !*path || !buf)
1109 return false;
1110 char *s = path;
1111 char *d = buf;
1112 *d = '\0';
1113 while (*s) {
1114 if (*s == '/' || *s == '\\') {
1115 d = buf;
1116 } else {
1117 *d++ = *s;
1118 }
1119 s++;
1120 }
1121 *d = '\0';
1122 if (d == buf)
1123 return false;
1124 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 1324 of file futil.c.

1325 {
1326 if (spec == nullptr || *spec == '\0')
1327 return 0;
1328 char tmp_s[MAXLEN];
1329 char *s;
1330 s = spec;
1331 char *d;
1332 d = tmp_s;
1333 uint l = 0;
1334 while (*s != '\0') {
1335 if (*s == ' ')
1336 break;
1337 if (*s == '\"' || *s == '\'') {
1338 s++;
1339 continue;
1340 ;
1341 }
1342 *d++ = *s++;
1343 l++;
1344 }
1345 *d = '\0';
1346 strnz__cpy(spec, tmp_s, MAXLEN - 1);
1347 l = strlen(spec);
1348 return l;
#define MAXLEN
Definition curskeys.c:15
size_t strnz__cpy(char *, const char *, size_t)
safer alternative to strncpy
Definition futil.c:537

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 743 of file futil.c.

743 {
744 if (s == nullptr)
745 return false;
746 while (*s != '\0') {
747 if (*s == old_chr)
748 *s = new_chr;
749 s++;
750 }
751 return true;
752}

Referenced by parse_menu_description().

Here is the caller graph for this function:

◆ destroy_argv()

int destroy_argv ( uint 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 487 of file futil.c.

487 {
488 for (uint i = 0; i < argc; i++) {
489 if (argv[i] != nullptr) {
490 free(argv[i]);
491 argv[i] = nullptr;
492 }
493 }
494 argc = 0;
495 return argc;
496}

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 1132 of file futil.c.

1133 {
1134 if (!path || !*path || !buf)
1135 return false;
1136 char tmp_str[MAXLEN];
1137 strnz__cpy(tmp_str, path, MAXLEN);
1138 char *s = tmp_str;
1139 while (*s++)
1140 ;
1141 while (tmp_str < --s) {
1142 if (*s == '/' || *s == '\\') {
1143 *s = '\0';
1144 break;
1145 }
1146 }
1147 while (tmp_str < --s && (*s == '/' || *s == '\\'))
1148 *s = '\0';
1149 char *d = buf;
1150 *d = '\0';
1151 s = tmp_str;
1152 while (*s) {
1153 *d++ = *s++;
1154 }
1155 *d = '\0';
1156 if (d == buf)
1157 return false;
1158 return true;

References strnz__cpy().

Here is the call graph for this function:

◆ expand_tilde()

bool expand_tilde ( char * str,
uint 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 963 of file futil.c.

964 {
965 if (str == nullptr || *str == '\0')
966 return false;
967 const char tgt[3] = "~/";
968 char path[MAXLEN];
969 char *e = getenv("HOME");
970 strnz__cpy(path, e, MAXLEN - 1);
971 strnz__cat(path, "/", MAXLEN - 1);
972 char *tmp;
973 tmp = rep_substring(str, tgt, path);
974 strnz__cpy(str, tmp, path_maxlen - 1);
975 free(tmp);
976 return true;
size_t strnz__cat(char *, const char *, size_t)
safer alternative to strncat
Definition futil.c:566
char * rep_substring(const char *, const char *, const char *)
Replace all occurrences of "tgt_s" in "org_s" with "rep_s".
Definition futil.c:1423

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 1047 of file futil.c.

1048 {
1049 char proc_path[MAXLEN];
1050
1051 snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", fd);
1052 ssize_t len = readlink(proc_path, out_path, MAXLEN - 1);
1053 if (len == -1)
1054 return nullptr;
1055 out_path[len] = '\0';
1056 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 890 of file futil.c.

891 {
892 if (fs == nullptr || *fs == '\0' || file_name == nullptr) {
893 if (file_name != nullptr)
894 *file_name = '\0';
895 return false;
896 }
897 char *d, *l, *s;
898 l = nullptr;
899 s = fs;
900 while (*s != '\0') {
901 if (*s == '/')
902 l = s;
903 s++;
904 }
905 if (l == nullptr)
906 s = fs;
907 else
908 s = ++l;
909 d = file_name;
910 while (*s != '\0')
911 *d++ = *s++;
912 *d = '\0';
913 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 863 of file futil.c.

864 {
865 if (fs == nullptr || *fs == '\0' || fp == nullptr) {
866 if (fp != nullptr)
867 *fp = '\0';
868 return false;
869 }
870 char *d, *l, *s;
871 s = fp;
872 d = fs;
873 l = nullptr;
874 while (*s != '\0') {
875 if (*s == '/')
876 l = d;
877 *d++ = *s++;
878 }
879 if (l == nullptr)
880 *fp = '\0'; // no slash, so no path
881 else
882 *l = '\0';
883 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 296 of file futil.c.

296 {
297 struct tm tmv;
298 localtime_r(&t, &tmv);
299 strftime(buf, n, "%Y-%m-%dT%H:%M:%S", &tmv);
300 return buf;
301}

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 169 of file futil.c.

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

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,
uint 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 347 of file futil.c.

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

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 307 of file futil.c.

307 {
308 static char buf[32];
309 time_t t = time(NULL);
310 format_local_timestamp(t, buf, sizeof buf);
311 return buf;
312}
char * format_local_timestamp(time_t, char *, size_t)
Formats a time_t as an ISO 8601 string in local time.
Definition futil.c:296

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 320 of file futil.c.

320 {
321 uid_t uid = getuid();
322 struct passwd *pw = getpwuid(uid);
323 if (pw == NULL)
324 return nullptr;
325 ssnprintf(user_str, maxlen - 1, "%s (%u)", pw->pw_name, (uint)uid);
326 return user_str;
327}
size_t ssnprintf(char *, size_t, const char *,...)
ssnprintf was designed to be a safer alternative to snprintf.
Definition futil.c:413

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 1355 of file futil.c.

1356 {
1357 struct stat statbuf;
1358 if (stat(path, &statbuf) == 0)
1359 if (S_ISDIR(statbuf.st_mode))
1360 return true;
1361 return false;

Referenced by main().

Here is the caller graph for this function:

◆ is_hex_str()

bool is_hex_str ( char * str,
uint 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 202 of file futil.c.

202 {
203 char *s = str;
204 char *e;
205 if (s == NULL || *s == '\0')
206 return false;
207 e = (s + len + 1);
208 while (s < e && *s != '\0') {
209 if (!isxdigit(*s)) {
210 return false;
211 }
212 s++;
213 }
214 if ((uint)(s - str) != len)
215 return false;
216 return true;
217}

◆ 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 153 of file futil.c.

153 {
154 // is fut newer than control?
155 struct stat control_st, fut_st;
156 if (!stat(control, &control_st))
157 if (!lstat(fut, &fut_st))
158 if (fut_st.st_mtime > control_st.st_mtime)
159 return true;
160 return false;
161}

◆ 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 1368 of file futil.c.

1369 {
1370 struct stat link_stat;
1371 struct stat target_stat;
1372
1373 if (lstat(path, &link_stat) == 0)
1374 if (S_ISLNK(link_stat.st_mode))
1375 if (stat(path, &target_stat) == 0)
1376 if (S_ISDIR(target_stat.st_mode))
1377 return true; // symbolic link to a directory
1378 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 1383 of file futil.c.

1384 {
1385 regex_t regex;
1386 uint ret = regcomp(&regex, pattern, REG_EXTENDED);
1387 regfree(&regex);
1388 if (ret == 0)
1389 return true;
1390 return false;

Referenced by main().

Here is the caller graph for this function:

◆ iso8601_time()

char * iso8601_time ( char * buf,
uint 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 257 of file futil.c.

257 {
258 struct tm *tp = local ? localtime(t) : gmtime(t);
259 if (local) {
260 strftime(buf, n, "%Y-%m-%dT%H:%M:%S%z", tp);
261 } else {
262 strftime(buf, n, "%Y-%m-%dT%H:%M:%SZ", tp);
263 }
264 return buf;
265}

◆ 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 1270 of file futil.c.

1271 {
1272 if (file_name == nullptr || *file_name == '\0' || file_spec == nullptr)
1273 return false;
1274 char path[MAXLEN];
1275 char ifn[MAXLEN];
1276 char *p, *fnp, *dir;
1277
1278 canonicalize_file_spec(file_name);
1279 strnz__cpy(ifn, file_name, MAXLEN - 1);
1280 fnp = ifn;
1281 while (*fnp && *fnp != '/')
1282 fnp++;
1283 if (*fnp == '/')
1284 return false;
1285 if ((p = getenv("PATH")) == nullptr)
1286 return false;
1287 strnz__cpy(path, p, MAXLEN - 1);
1288 dir = strtok(path, ":");
1289 while (dir != nullptr) {
1290 strnz__cpy(file_spec, dir, MAXLEN - 1);
1291 strnz__cat(file_spec, "/", MAXLEN - 1);
1292 strnz__cat(file_spec, file_name, MAXLEN - 1);
1293 if (access(file_spec, F_OK) == 0) {
1294 return true;
1295 }
1296 dir = strtok(nullptr, ":");
1297 }
1298 return false;
size_t canonicalize_file_spec(char *)
Removes quotes and trims at first space.
Definition futil.c:1324

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 1303 of file futil.c.

1304 {
1305 expand_tilde(dir, MAXLEN - 1);
1306 if (!verify_dir(dir, S_WCOK | S_QUIET)) {
1307 if (!mkdir(dir, 0755)) {
1309 ssnprintf(em0, MAXLEN - 1, "%s, line: %d", __FILE__, __LINE__ - 2);
1310 strnz__cpy(em1, "mkdir ", MAXLEN - 1);
1311 strnz__cat(em1, dir, MAXLEN - 1);
1312 strnz__cat(em1, " failed", MAXLEN - 1);
1313 strerror_r(errno, em2, MAXLEN - 1);
1314 display_error(em0, em1, em2, nullptr);
1315 return false;
1316 }
1317 return true;
1318 }
1319 return true;
#define S_QUIET
Definition cm.h:328
#define S_WCOK
Definition cm.h:327
char em1[MAXLEN]
Definition dwin.c:143
char em2[MAXLEN]
Definition dwin.c:144
char em0[MAXLEN]
Definition dwin.c:142
int display_error(char *msg0, char *msg1, char *msg2, char *msg3)
Display an error message window or print to stderr.
Definition dwin.c:778
bool expand_tilde(char *str, uint path_maxlen)
Replaces "~/" in string with the user's home directory.
Definition futil.c:963
bool verify_dir(char *, uint)
Verifies that the directory specified by "spec" exists and is accessible with the permissions specifi...
Definition futil.c:1172

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 846 of file futil.c.

847 {
848 if (fs == nullptr || *fs == '\0')
849 return false;
850 while (*fs != '\0') {
851 if (*fs == '\\')
852 *fs = '/';
853 fs++;
854 }
855 return true;

◆ open_cmenu_log()

void open_cmenu_log ( )

Open new C-Menu log file.

Definition at line 1650 of file futil.c.

1651 {
1652 char ttyname[MAXLEN];
1653 char cmenu_user[MAXLEN];
1654 char *p;
1655 cmenu_log_fd = open("/tmp/cmenu.log", O_WRONLY | O_CREAT | O_TRUNC,
1656 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
1657 p = getenv("USER");
1658 strnz__cpy(cmenu_user, p, MAXLEN - 1);
1659 if (ttyname_r(STDERR_FILENO, ttyname, sizeof(ttyname)) == 0)
1660 strnz__cpy(em0, ttyname, MAXLEN - 1);
1661 ssnprintf(em0, MAXLEN - 1, "C-Menu started by user '%s' on terminal '%s'\n",
1662 cmenu_user, ttyname);
int cmenu_log_fd
Definition futil.c:47
void write_cmenu_log(char *msg)
Write message to C-Menu log file without timestamp.
Definition futil.c:1684

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 273 of file futil.c.

273 {
274 struct tm tmv;
275 memset(&tmv, 0, sizeof tmv);
276 tmv.tm_isdst = -1;
277
278 if (strptime(s, "%Y-%m-%dT%H:%M:%S", &tmv) == NULL)
279 return false;
280
281 time_t t = mktime(&tmv);
282 if (t == (time_t)-1)
283 return false;
284
285 *out = t;
286 return true;
287}

◆ 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 1423 of file futil.c.

1424 {
1425 if (org_s == nullptr || tgt_s == nullptr || rep_s == nullptr)
1426 return nullptr;
1427 if (*org_s == '\0' || *tgt_s == '\0' || *rep_s == '\0')
1428 return nullptr;
1429 if (strstr(org_s, tgt_s) == nullptr)
1430 return strdup(org_s);
1431 if (strstr(rep_s, tgt_s) != nullptr)
1432 return nullptr;
1433 if (tgt_s == rep_s || tgt_s == org_s || rep_s == org_s)
1434 return strdup(org_s);
1435 if (strcmp(org_s, tgt_s) == 0)
1436 return strdup(rep_s);
1437 char *out_s, *ip, *tmp;
1438 uint tgt_l = strlen(tgt_s);
1439 uint rep_l = strlen(rep_s);
1440 uint head_l;
1441 uint n = 0;
1442 ip = (char *)org_s;
1443 while ((tmp = strstr(ip, tgt_s)) != nullptr) {
1444 n++;
1445 ip = tmp + tgt_l;
1446 }
1447 out_s = malloc(strlen(org_s) + (rep_l - tgt_l) * n + 1);
1448 if (!out_s) {
1449 return nullptr;
1450 }
1451 tmp = out_s;
1452 ip = (char *)org_s;
1453 while (n--) {
1454 char *p = strstr(ip, tgt_s);
1455 head_l = p - ip;
1456 strnz__cpy(tmp, ip, head_l);
1457 tmp += head_l;
1458 strnz__cpy(tmp, rep_s, MAXLEN - 1);
1459 tmp += rep_l;
1460 ip += head_l + tgt_l;
1461 }
1462 strnz__cpy(tmp, ip, MAXLEN - 1);
1463 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 413 of file futil.c.

413 {
414 size_t n;
415 va_list args;
416
417 va_start(args, format);
418 n = vsnprintf(buf, buf_size, format, args);
419 va_end(args);
420
421 return n;
422}

Referenced by action_disposition(), answer_yn(), compile_chyron(), debug_out(), display_error(), display_line(), display_split_line(), enter_file_spec(), fork_exec(), form_desc_error(), form_parse_desc(), form_process(), form_write(), get_user_str(), handle_signal(), init_view_full_screen(), lp(), mapp_initialization(), menu_engine(), mk_dir(), new_init(), new_pick(), new_view(), open_cmenu_log(), open_pick_win(), parse_menu_description(), Perror(), picker(), set_chyron_key(), set_chyron_key_cb(), signal_handler(), stdio_fdnames(), stdio_names(), ui_add_pair(), verify_dir(), verify_file(), view_cmd_processor(), view_init_input(), 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,
uint 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 683 of file futil.c.

683 {
684 char *e;
685 if (s == nullptr || d == nullptr || Withstr == nullptr || l == 0) {
686 if (d != nullptr && l > 0)
687 *d = '\0';
688 return false;
689 }
690 e = d + l;
691 while (*s != '\0' && d < e) {
692 if (*s == ReplaceChr) {
693 while (*Withstr != '\0' && d < e)
694 *d++ = *Withstr++;
695 s++;
696 } else
697 *d++ = *s++;
698 }
699 *d = '\0';
700 return true;
701}

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,
uint 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 433 of file futil.c.

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

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.
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 922 of file futil.c.

923 {
924 char *e;
925 double d;
926
927 if (!s || !*s)
928 return false;
929 d = strtod(s, &e);
930 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 501 of file futil.c.

501 {
502 if (s == nullptr || *s == '\0')
503 return false;
504 while (*s != '\0') {
505 if (*s >= 'A' && *s <= 'Z')
506 *s = *s + 'a' - 'A';
507 s++;
508 }
509 return true;
510}

Referenced by 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 515 of file futil.c.

515 {
516 if (s == nullptr || *s == '\0')
517 return false;
518 while (*s != '\0') {
519 if (*s >= 'a' && *s <= 'z')
520 *s = *s + 'A' - 'a';
521 s++;
522 }
523 return true;
524}

◆ 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 822 of file futil.c.

823 {
824 size_t l = 0;
825 while (*s) {
826 if (*s == '\033') {
827 while (*s && *s != 'm' && *s != 'K')
828 s++;
829 if (*s == 'm' || *s == 'K')
830 s++;
831 continue;
832 } else {
833 if ((unsigned char)*s <= 127) {
834 *d++ = *s++;
835 l++;
836 } else
837 s++;
838 }
839 }
840 *d = '\0';
841 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 711 of file futil.c.

711 {
712 if (s == nullptr)
713 return false;
714 uint l = strlen(s);
715 if (l > 1 && s[l - 1] == '\"') {
716 memmove(s, s + 1, l - 2);
717 s[l - 2] = '\0';
718 }
719 return true;
720}

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 726 of file futil.c.

726 {
727 if (s == nullptr || strlen(s) < 2)
728 return false;
729 uint l = strlen(s);
730 if (l > 1 && s[0] == '\"' && s[l - 1] == '\"') {
731 memmove(s, s + 1, l - 2);
732 s[l - 2] = '\0';
733 return true;
734 }
735 return false;
736}

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 626 of file futil.c.

626 {
627 char *e;
628 size_t len = 0;
629 if (s == nullptr || *s == '\0' || max_len == 0)
630 return 0;
631 e = s + max_len;
632 while (*s != '\0' && *s != '\n' && *s != '\r' && s < e) {
633 s++;
634 len++;
635 }
636 *s++ = '\n';
637 len++;
638 *s = '\0';
639 return (len);
640}

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 608 of file futil.c.

608 {
609 char *e;
610 size_t len = 0;
611 if (s == nullptr || *s == '\0' || max_len == 0)
612 return 0;
613 e = s + max_len;
614 while (*s != '\0' && *s != '\n' && *s != '\r' && s < e) {
615 s++;
616 len++;
617 }
618 *s = '\0';
619 return (len);
620}

Referenced by answer_yn(), border_ysplit_text(), display_error(), display_form(), enter_file_spec(), form_display_fields(), form_fmt_field(), 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 566 of file futil.c.

566 {
567 char *e;
568 size_t len = 0;
569 if (s == nullptr || d == nullptr || max_len == 0) {
570 if (d != nullptr && max_len > 0)
571 *d = '\0';
572 return 0;
573 }
574 e = d + max_len;
575 while (*d != '\0' && *d != '\n' && *d != '\r' && d < e) {
576 d++;
577 len++;
578 }
579 while (*s != '\0' && *s != '\n' && *s != '\r' && d < e) {
580 *d++ = *s++;
581 len++;
582 }
583 *d = '\0';
584 return len;
585}

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(), 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_ts(), 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 537 of file futil.c.

537 {
538 char *e;
539 size_t len = 0;
540 if (s == nullptr || d == nullptr || max_len == 0) {
541 if (d != nullptr && max_len > 0)
542 *d = '\0';
543 return 0;
544 }
545 e = d + max_len;
546 while (*s != '\0' && *s != '\n' && *s != '\r' && d < e) {
547 *d++ = *s++;
548 len++;
549 }
550 *d = '\0';
551 return len;
552}

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(), log_strnz(), main(), mapp_initialization(), menu_cmd_processor(), mk_dir(), new_form(), new_pick_view(), new_view_file(), open_cmenu_log(), output_objects(), parse_menu_description(), Perror(), picker(), popup_ckeys(), process_config_file(), process_config_files(), rep_substring(), save_object(), search(), stdio_fdnames(), stdio_names(), ui_box_surface_new(), verify_dir(), verify_file(), verify_spec_arg(), view_cmd_processor(), view_display_help(), view_file(), view_init_input(), whence(), write_cmenu_log_ts(), 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 647 of file futil.c.

647 {
648 char *p, *ms, *e;
649 size_t m;
650 if (s == nullptr || *s == '\0' || l == 0)
651 return nullptr;
652 for (p = s, m = 1; *p != '\0'; p++, m++)
653 ;
654 ms = p = (char *)malloc(m);
655 if (ms != nullptr) {
656 e = ms + l;
657 while (*s != '\0' && *s != '\n' && *s != '\r' && p < e)
658 *p++ = *s++;
659 *p = '\0';
660 }
661 return ms;
662}

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 590 of file futil.c.

590 {
591 size_t l = 0;
592 if (s == nullptr || *s == '\0')
593 return 0;
594 while (*s != '\0' && *s != '\n' && *s != '\r') {
595 s++;
596 l++;
597 }
598 *s = '\0';
599 return l;
600}

◆ 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 384 of file futil.c.

384 {
385 if (s == nullptr || *s == '\0')
386 return 0;
387 char *p = s;
388 char *d = s;
389 while (*p == ' ')
390 p++;
391 while (*p != '\0')
392 *d++ = *p++;
393 while (*(d - 1) == ' ' && d > s)
394 d--;
395 *d = '\0';
396 return (size_t)(d - s);
397}

Referenced by form_fmt_field(), form_parse_desc(), left_justify(), menu_cmd_processor(), parse_menu_description(), right_justify(), 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 1009 of file futil.c.

1010 {
1011 if (!filename || !*filename || !buf)
1012 return false;
1013 char *s = filename;
1014 char *d = buf;
1015 *d = '\0';
1016 while (*s)
1017 s++;
1018 while (filename < --s) {
1019 if (*s == '.') {
1020 break;
1021 }
1022 }
1023 if (*s != '.') {
1024 while (*filename)
1025 *d++ = *filename++;
1026 } else {
1027 while (filename < s) {
1028 *d++ = *filename++;
1029 }
1030 }
1031 *d = '\0';
1032 if (d == buf)
1033 return false;
1034 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 981 of file futil.c.

982 {
983 if (!dir)
984 return false;
985 char *p;
986
987 if (!dir || !*dir)
988 return false;
989 p = dir;
990 while (*p++ != '\0') {
991 if (*p == ' ' || *p == '\t' || *p == '\n') {
992 *p = '\0';
993 break;
994 }
995 }
996 --p;
997 while (--p > dir && *p == '/') {
998 if (*(p - 1) != '~')
999 *p = '\0';
1000 }
1001 return true;

Referenced by derive_file_spec().

Here is the caller graph for this function:

◆ 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 225 of file futil.c.

225 {
226 char *s = str;
227 char *e;
228 char *d;
229 if (s == NULL || *s == '\0')
230 return false;
231 if (*s != '#')
232 return false;
233 d = dst;
234 *d++ = *s++;
235 e = (s + 6);
236 while (s < e && *s != '\0') {
237 if (!isxdigit(*s)) {
238 return false;
239 }
240 *d++ = *s++;
241 }
242 *d = '\0';
243 if ((uint)(s - str) != 7)
244 return false;
245 return true;
246}

Referenced by process_config_file().

Here is the caller graph for this function:

◆ verify_dir()

bool verify_dir ( char * spec,
uint 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 1172 of file futil.c.

1173 {
1174 if (spec == nullptr || *spec == '\0')
1175 return false;
1176 expand_tilde(spec, MAXLEN);
1177 struct stat sb;
1178 errno = 0;
1179 src_line = 0;
1180 uint mode = imode & ~(S_WCOK | S_QUIET);
1181 if (faccessat(AT_FDCWD, spec, mode, AT_EACCESS) != 0) {
1182 src_line = __LINE__ - 2;
1183 src_name = __FILE__;
1184 strnz__cpy(fn, "faccessat", MAXLEN - 1);
1185 } else {
1186 if (fstatat(AT_FDCWD, spec, &sb, 0) != 0) {
1187 src_line = __LINE__ - 1;
1188 src_name = __FILE__;
1189 strnz__cpy(fn, "fstatat", MAXLEN - 1);
1190 } else {
1191 if ((sb.st_mode & S_IFMT) != S_IFDIR) {
1192 src_line = __LINE__ - 1;
1193 src_name = __FILE__;
1194 strnz__cpy(fn, "verify_file", MAXLEN - 1);
1195 strnz__cpy(em2, "Not a regular file.", MAXLEN - 1);
1196 }
1197 }
1198 }
1199 if (src_line != 0) {
1200 if (!(mode & S_QUIET)) {
1201 ssnprintf(em0, MAXLEN - 1, "%s failed in %s at line %d", fn,
1203 strnz__cpy(em1, spec, MAXLEN - 1);
1204 strnz__cpy(em3, "Check the file", MAXLEN - 1);
1206 }
1207 return false;
1208 }
1209 return true;
char fn[MAXLEN]
Definition dwin.c:141
char em3[MAXLEN]
Definition dwin.c:145
uint src_line
Definition dwin.c:139
char * src_name
Definition dwin.c:140

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,
uint 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 1223 of file futil.c.

1224 {
1225 if (in_spec == nullptr || *in_spec == '\0')
1226 return false;
1227 struct stat sb;
1228 char spec[MAXLEN];
1229 strnz__cpy(spec, in_spec, MAXLEN - 1);
1230 uint mode = imode & ~(S_WCOK | S_QUIET);
1231 errno = 0;
1232 src_line = 0;
1234 expand_tilde(spec, MAXLEN);
1235 if ((faccessat(AT_FDCWD, spec, mode, AT_EACCESS)) != 0) {
1236 src_line = __LINE__ - 1;
1237 src_name = __FILE__;
1238 strnz__cpy(fn, "faccessat", MAXLEN - 1);
1239 } else {
1240 if ((fstatat(AT_FDCWD, spec, &sb, 0)) != 0) {
1241 src_line = __LINE__ - 1;
1242 src_name = __FILE__;
1243 strnz__cpy(fn, "fstatat", MAXLEN - 1);
1244 } else {
1245 if ((sb.st_mode & S_IFMT) != S_IFREG) {
1246 src_line = __LINE__ - 1;
1247 src_name = __FILE__;
1248 strnz__cpy(fn, "verify_file", MAXLEN - 1);
1249 strnz__cpy(em2, "Not a regular file.", MAXLEN - 1);
1250 }
1251 }
1252 }
1253 if (src_line != 0) {
1254 if (imode & S_QUIET)
1255 return false;
1256 ssnprintf(em0, MAXLEN - 1, "%s failed in %s at line %d", fn, src_name,
1257 src_line);
1258 strnz__cpy(em1, spec, MAXLEN - 1);
1259 strnz__cpy(em3, "Check the file", MAXLEN - 1);
1261 return false;
1262 }
1263 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:

◆ write_cmenu_log()

void write_cmenu_log ( char * msg)

Write message to C-Menu log file without timestamp.

Parameters
msg- string to write to log file

Definition at line 1684 of file futil.c.

1685 {
1686 write(cmenu_log_fd, msg, strlen(msg));
1687 write(cmenu_log_fd, "\n", 1);
1688 return;

References cmenu_log_fd.

Referenced by log_cc_buf(), log_split_lines(), log_stripped_line_out(), log_strnz(), and open_cmenu_log().

Here is the caller graph for this function:

◆ write_cmenu_log_ts()

void write_cmenu_log_ts ( char * msg)

Write message to C-Menu log file with timestamp.

Parameters
msg- string to write to log file

Definition at line 1668 of file futil.c.

1669 {
1670 char time_buf[100];
1671 time_t now = time(NULL);
1672 struct tm *t = localtime(&now);
1673 strftime(time_buf, sizeof(time_buf), "%Y-%m-%dT%H:%M:%S%z", t);
1674 strnz__cpy(em1, time_buf, MAXLEN - 1);
1675 strnz__cat(em1, " ", MAXLEN - 1);
1676 strnz__cat(em1, msg, MAXLEN - 1);
1677 write(cmenu_log_fd, em1, strlen(em1));
1678 write(cmenu_log_fd, "\n", 1);
1679 return;

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

Here is the call graph for this function: