diff options
Diffstat (limited to 'xstrings.c')
-rw-r--r-- | xstrings.c | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/xstrings.c b/xstrings.c new file mode 100644 index 0000000..395def5 --- /dev/null +++ b/xstrings.c @@ -0,0 +1,473 @@ +/* $XTermId: xstrings.c,v 1.50 2012/03/30 10:54:12 tom Exp $ */ + +/* + * Copyright 2000-2011,2012 by Thomas E. Dickey + * + * All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization. + */ + +#include <xterm.h> + +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include <xstrings.h> + +static void +alloc_pw(struct passwd *target, struct passwd *source) +{ + *target = *source; + /* we care only about these strings */ + target->pw_dir = x_strdup(source->pw_dir); + target->pw_name = x_strdup(source->pw_name); + target->pw_shell = x_strdup(source->pw_shell); +} + +void +x_appendargv(char **target, char **source) +{ + if (target && source) { + target += x_countargv(target); + while ((*target++ = *source++) != 0) ; + } +} + +char * +x_basename(char *name) +{ + char *cp; + + cp = strrchr(name, '/'); +#ifdef __UNIXOS2__ + if (cp == 0) + cp = strrchr(name, '\\'); +#endif + return (cp ? cp + 1 : name); +} + +unsigned +x_countargv(char **argv) +{ + unsigned result = 0; + if (argv) { + while (*argv++) { + ++result; + } + } + return result; +} + +/* + * Decode a hexadecimal string, returning the decoded string. + * On return, 'next' points to the first character not part of the input. + * The caller must free the result. + */ +char * +x_decode_hex(const char *source, const char **next) +{ + char *result = 0; + int pass; + size_t j, k; + + for (pass = 0; pass < 2; ++pass) { + for (j = k = 0; isxdigit(CharOf(source[j])); ++j) { + if ((pass != 0) && (j & 1) != 0) { + result[k++] = (char) ((x_hex2int(source[j - 1]) << 4) + | x_hex2int(source[j])); + } + } + *next = (source + j); + if ((j & 1) == 0) { + if (pass) { + result[k] = '\0'; + } else { + result = malloc(++j); + if (result == 0) + break; /* not enough memory */ + } + } else { + break; /* must have an even number of digits */ + } + } + return result; +} + +/* + * Encode a string into hexadecimal, returning the encoded string. + * The caller must free the result. + */ +char * +x_encode_hex(const char *source) +{ + size_t need = (strlen(source) * 2) + 1; + char *result = malloc(need); + + if (result != 0) { + unsigned j, k; + for (j = k = 0; source[j] != '\0'; ++j) { + sprintf(result + k, "%02X", CharOf(source[j])); + k += 2; + } + } + return result; +} + +char * +x_getenv(const char *name) +{ + char *result; + result = x_strdup(x_nonempty(getenv(name))); + TRACE2(("getenv(%s) %s\n", name, result)); + return result; +} + +static char * +login_alias(char *login_name, uid_t uid, struct passwd *in_out) +{ + /* + * If the logon-name differs from the value we get by looking in the + * password file, check if it does correspond to the same uid. If so, + * allow that as an alias for the uid. + */ + if (!IsEmpty(login_name) + && strcmp(login_name, in_out->pw_name)) { + struct passwd pw2; + + if (x_getpwnam(login_name, &pw2)) { + uid_t uid2 = pw2.pw_uid; + struct passwd pw3; + + if (x_getpwuid(uid, &pw3) + && ((uid_t) pw3.pw_uid == uid2)) { + /* use the other passwd-data including shell */ + alloc_pw(in_out, &pw2); + } else { + login_name = NULL; + } + } + } + return login_name; +} + +/* + * Call this with in_out pointing to data filled in by x_getpwnam() or by + * x_getpwnam(). It finds the user's logon name, if possible. As a side + * effect, it updates in_out to fill in possibly more-relevant data, i.e., + * in case there is more than one alias for the same uid. + */ +char * +x_getlogin(uid_t uid, struct passwd *in_out) +{ + char *login_name = NULL; + + login_name = login_alias(x_getenv("LOGNAME"), uid, in_out); + if (IsEmpty(login_name)) { + login_name = login_alias(x_getenv("USER"), uid, in_out); + } +#ifdef HAVE_GETLOGIN + /* + * Of course getlogin() will fail if we're started from a window-manager, + * since there's no controlling terminal to fuss with. For that reason, we + * tried first to get something useful from the user's $LOGNAME or $USER + * environment variables. + */ + if (IsEmpty(login_name)) { + TRACE2(("...try getlogin\n")); + login_name = login_alias(getlogin(), uid, in_out); + } +#endif + + if (IsEmpty(login_name)) + login_name = in_out->pw_name; + if (!IsEmpty(login_name)) + login_name = x_strdup(login_name); + + TRACE2(("x_getloginid ->%s\n", NonNull(login_name))); + return login_name; +} + +/* + * Simpler than getpwnam_r, retrieves the passwd result by name and stores the + * result via the given pointer. On failure, wipes the data to prevent use. + */ +Boolean +x_getpwnam(const char *name, struct passwd * result) +{ + struct passwd *ptr = getpwnam(name); + Boolean code; + + if (ptr != 0 && OkPasswd(ptr)) { + code = True; + alloc_pw(result, ptr); + } else { + code = False; + memset(result, 0, sizeof(*result)); + } + return code; +} + +/* + * Simpler than getpwuid_r, retrieves the passwd result by uid and stores the + * result via the given pointer. On failure, wipes the data to prevent use. + */ +Boolean +x_getpwuid(uid_t uid, struct passwd * result) +{ + struct passwd *ptr = getpwuid((uid_t) uid); + Boolean code; + + if (ptr != 0 && OkPasswd(ptr)) { + code = True; + alloc_pw(result, ptr); + } else { + code = False; + memset(result, 0, sizeof(*result)); + } + TRACE2(("x_getpwuid(%d) %d\n", (int) uid, (int) code)); + return code; +} + +/* + * Decode a single hex "nibble", returning the nibble as 0-15, or -1 on error. + */ +int +x_hex2int(int c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +/* + * Check if the given string is nonnull/nonempty. If so, return a pointer + * to the beginning of its content, otherwise return null. + */ +String +x_nonempty(String s) +{ + if (s != 0) { + if (*s == '\0') { + s = 0; + } else { + s = x_skip_blanks(s); + if (*s == '\0') + s = 0; + } + } + return s; +} + +String +x_skip_blanks(String s) +{ + while (isspace(CharOf(*s))) + ++s; + return s; +} + +String +x_skip_nonblanks(String s) +{ + while (*s != '\0' && !isspace(CharOf(*s))) + ++s; + return s; +} + +/* + * Split a command-string into an argv[]-style array. + */ +char ** +x_splitargs(const char *command) +{ + char **result = 0; + + if (command != 0) { + char *blob = x_strdup(command); + size_t count; + size_t n; + int state; + int pass; + + for (pass = 0; pass < 2; ++pass) { + for (n = count = 0, state = 0; command[n] != '\0'; ++n) { + switch (state) { + case 0: + if (!isspace(CharOf(command[n]))) { + state = 1; + if (pass) + result[count] = blob + n; + ++count; + } else { + blob[n] = '\0'; + } + break; + case 1: + if (isspace(CharOf(command[n]))) { + blob[n] = '\0'; + state = 0; + } + break; + } + } + if (!pass) { + result = TypeCallocN(char *, count + 1); + if (!result) + break; + } + } + } else { + result = TypeCalloc(char *); + } + return result; +} + +int +x_strcasecmp(const char *s1, const char *s2) +{ + size_t len = strlen(s1); + + if (len != strlen(s2)) + return 1; + + return x_strncasecmp(s1, s2, (unsigned) len); +} + +int +x_strncasecmp(const char *s1, const char *s2, unsigned n) +{ + while (n-- != 0) { + char c1 = x_toupper(*s1); + char c2 = x_toupper(*s2); + if (c1 != c2) + return 1; + if (c1 == 0) + break; + s1++, s2++; + } + + return 0; +} + +/* + * Allocates a copy of a string + */ +char * +x_strdup(const char *s) +{ + char *result = 0; + + if (s != 0) { + char *t = CastMallocN(char, strlen(s) + 1); + if (t != 0) { + strcpy(t, s); + } + result = t; + } + return result; +} + +/* + * Returns a pointer to the first occurrence of s2 in s1, + * or NULL if there are none. + */ +char * +x_strindex(char *s1, const char *s2) +{ + char *s3; + size_t s2len = strlen(s2); + + while ((s3 = strchr(s1, *s2)) != NULL) { + if (strncmp(s3, s2, s2len) == 0) + return (s3); + s1 = ++s3; + } + return (NULL); +} + +/* + * Trims leading/trailing spaces from a copy of the string. + */ +char * +x_strtrim(const char *source) +{ + char *result; + char *s; + char *d; + + if (source != 0 && *source != '\0') { + char *t = x_strdup(source); + s = t; + d = s; + while (isspace(CharOf(*s))) + ++s; + while ((*d++ = *s++) != '\0') { + ; + } + if (*t != '\0') { + s = t + strlen(t); + while (s != t && isspace(CharOf(s[-1]))) { + *--s = '\0'; + } + } + result = t; + } else { + result = x_strdup(""); + } + return result; +} + +/* + * Avoid using system locale for upper/lowercase conversion, since there are + * a few locales where toupper(tolower(c)) != c. + */ +char +x_toupper(int ch) +{ + static char table[256]; + char result = table[CharOf(ch)]; + + if (result == '\0') { + unsigned n; + const char *s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + for (n = 0; n < sizeof(table); ++n) { + table[n] = (char) n; + } + for (n = 0; s[n] != '\0'; ++n) { + table[CharOf(s[n])] = s[n % 26]; + } + result = table[CharOf(ch)]; + } + + return result; +} |