"Fossies" - the Fresh Open Source Software Archive

Member "xterm-379/xstrings.c" (16 Nov 2022, 12140 Bytes) of package /linux/misc/xterm-379.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "xstrings.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 375_vs_376.

    1 /* $XTermId: xstrings.c,v 1.79 2022/11/16 23:54:32 tom Exp $ */
    2 
    3 /*
    4  * Copyright 2000-2020,2022 by Thomas E. Dickey
    5  *
    6  *                         All Rights Reserved
    7  *
    8  * Permission is hereby granted, free of charge, to any person obtaining a
    9  * copy of this software and associated documentation files (the
   10  * "Software"), to deal in the Software without restriction, including
   11  * without limitation the rights to use, copy, modify, merge, publish,
   12  * distribute, sublicense, and/or sell copies of the Software, and to
   13  * permit persons to whom the Software is furnished to do so, subject to
   14  * the following conditions:
   15  *
   16  * The above copyright notice and this permission notice shall be included
   17  * in all copies or substantial portions of the Software.
   18  *
   19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   22  * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
   23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   26  *
   27  * Except as contained in this notice, the name(s) of the above copyright
   28  * holders shall not be used in advertising or otherwise to promote the
   29  * sale, use or other dealings in this Software without prior written
   30  * authorization.
   31  */
   32 
   33 #include <xterm.h>
   34 
   35 #include <sys/types.h>
   36 #include <stdio.h>
   37 #include <string.h>
   38 #include <ctype.h>
   39 
   40 #include <xstrings.h>
   41 
   42 static void
   43 alloc_pw(struct passwd *target, struct passwd *source)
   44 {
   45     *target = *source;
   46     /* we care only about these strings */
   47     target->pw_dir = x_strdup(source->pw_dir);
   48     target->pw_name = x_strdup(source->pw_name);
   49     target->pw_shell = x_strdup(source->pw_shell);
   50 }
   51 
   52 static void
   53 free_pw(struct passwd *source)
   54 {
   55     free(source->pw_dir);
   56     free(source->pw_name);
   57     free(source->pw_shell);
   58 }
   59 
   60 void
   61 x_appendargv(char **target, char **source)
   62 {
   63     if (target && source) {
   64     target += x_countargv(target);
   65     while ((*target++ = *source++) != 0) ;
   66     }
   67 }
   68 
   69 char *
   70 x_basename(char *name)
   71 {
   72     char *cp;
   73 
   74     cp = strrchr(name, '/');
   75     return (cp ? cp + 1 : name);
   76 }
   77 
   78 unsigned
   79 x_countargv(char **argv)
   80 {
   81     unsigned result = 0;
   82     if (argv) {
   83     while (*argv++) {
   84         ++result;
   85     }
   86     }
   87     return result;
   88 }
   89 
   90 /*
   91  * Decode a hexadecimal string, returning the decoded string.
   92  * On return, 'next' points to the first character not part of the input.
   93  * The caller must free the result.
   94  */
   95 char *
   96 x_decode_hex(const char *source, const char **next)
   97 {
   98     char *result = 0;
   99     int pass;
  100     size_t j, k;
  101 
  102     for (pass = 0; pass < 2; ++pass) {
  103     for (j = k = 0; isxdigit(CharOf(source[j])); ++j) {
  104         if ((pass != 0) && (j & 1) != 0) {
  105         result[k++] = (char) ((CharOf(x_hex2int(source[j - 1])) << 4)
  106                       | CharOf(x_hex2int(source[j])));
  107         }
  108     }
  109     *next = (source + j);
  110     if ((j & 1) == 0) {
  111         if (pass) {
  112         result[k] = '\0';
  113         } else {
  114         result = malloc(++j);
  115         if (result == 0)
  116             break;  /* not enough memory */
  117         }
  118     } else {
  119         break;      /* must have an even number of digits */
  120     }
  121     }
  122     return result;
  123 }
  124 
  125 /*
  126  * Encode a string into hexadecimal, returning the encoded string.
  127  * The caller must free the result.
  128  */
  129 char *
  130 x_encode_hex(const char *source)
  131 {
  132     size_t need = (strlen(source) * 2) + 1;
  133     char *result = malloc(need);
  134 
  135     if (result != 0) {
  136     unsigned j, k;
  137     result[0] = '\0';
  138     for (j = k = 0; source[j] != '\0'; ++j) {
  139         sprintf(result + k, "%02X", CharOf(source[j]));
  140         k += 2;
  141     }
  142     }
  143     return result;
  144 }
  145 
  146 char *
  147 x_getenv(const char *name)
  148 {
  149     char *result;
  150     result = x_strdup(x_nonempty(getenv(name)));
  151     TRACE2(("getenv(%s) %s\n", name, result));
  152     return result;
  153 }
  154 
  155 static char *
  156 login_alias(char *login_name, uid_t uid, struct passwd *in_out)
  157 {
  158     /*
  159      * If the logon-name differs from the value we get by looking in the
  160      * password file, check if it does correspond to the same uid.  If so,
  161      * allow that as an alias for the uid.
  162      */
  163     if (!IsEmpty(login_name)
  164     && strcmp(login_name, in_out->pw_name)) {
  165     struct passwd pw2;
  166     Boolean ok2;
  167 
  168     if ((ok2 = x_getpwnam(login_name, &pw2))) {
  169         uid_t uid2 = pw2.pw_uid;
  170         struct passwd pw3;
  171         Boolean ok3;
  172 
  173         if ((ok3 = x_getpwuid(uid, &pw3))
  174         && ((uid_t) pw3.pw_uid == uid2)) {
  175         /* use the other passwd-data including shell */
  176         alloc_pw(in_out, &pw2);
  177         } else {
  178         FreeAndNull(login_name);
  179         }
  180         if (ok2)
  181         free_pw(&pw2);
  182         if (ok3)
  183         free_pw(&pw3);
  184     }
  185     }
  186     return login_name;
  187 }
  188 
  189 /*
  190  * Call this with in_out pointing to data filled in by x_getpwnam() or by
  191  * x_getpwnam().  It finds the user's logon name, if possible.  As a side
  192  * effect, it updates in_out to fill in possibly more-relevant data, i.e.,
  193  * in case there is more than one alias for the same uid.
  194  */
  195 char *
  196 x_getlogin(uid_t uid, struct passwd *in_out)
  197 {
  198     char *login_name;
  199 
  200     login_name = login_alias(x_getenv("LOGNAME"), uid, in_out);
  201     if (IsEmpty(login_name)) {
  202     free(login_name);
  203     login_name = login_alias(x_getenv("USER"), uid, in_out);
  204     }
  205 #ifdef HAVE_GETLOGIN
  206     /*
  207      * Of course getlogin() will fail if we're started from a window-manager,
  208      * since there's no controlling terminal to fuss with.  For that reason, we
  209      * tried first to get something useful from the user's $LOGNAME or $USER
  210      * environment variables.
  211      */
  212     if (IsEmpty(login_name)) {
  213     TRACE2(("...try getlogin\n"));
  214     free(login_name);
  215     login_name = login_alias(x_strdup(getlogin()), uid, in_out);
  216     }
  217 #endif
  218 
  219     if (IsEmpty(login_name)) {
  220     free(login_name);
  221     login_name = x_strdup(in_out->pw_name);
  222     }
  223 
  224     TRACE2(("x_getloginid ->%s\n", NonNull(login_name)));
  225     return login_name;
  226 }
  227 
  228 /*
  229  * Simpler than getpwnam_r, retrieves the passwd result by name and stores the
  230  * result via the given pointer.  On failure, wipes the data to prevent use.
  231  */
  232 Boolean
  233 x_getpwnam(const char *name, struct passwd *result)
  234 {
  235     struct passwd *ptr = getpwnam(name);
  236     Boolean code;
  237 
  238     if (ptr != 0 && OkPasswd(ptr)) {
  239     code = True;
  240     alloc_pw(result, ptr);
  241     } else {
  242     code = False;
  243     memset(result, 0, sizeof(*result));
  244     }
  245     return code;
  246 }
  247 
  248 /*
  249  * Simpler than getpwuid_r, retrieves the passwd result by uid and stores the
  250  * result via the given pointer.  On failure, wipes the data to prevent use.
  251  */
  252 Boolean
  253 x_getpwuid(uid_t uid, struct passwd *result)
  254 {
  255     struct passwd *ptr = getpwuid((uid_t) uid);
  256     Boolean code;
  257 
  258     if (ptr != 0 && OkPasswd(ptr)) {
  259     code = True;
  260     alloc_pw(result, ptr);
  261     } else {
  262     code = False;
  263     memset(result, 0, sizeof(*result));
  264     }
  265     TRACE2(("x_getpwuid(%d) %d\n", (int) uid, (int) code));
  266     return code;
  267 }
  268 
  269 /*
  270  * Decode a single hex "nibble", returning the nibble as 0-15, or -1 on error.
  271  */
  272 int
  273 x_hex2int(int c)
  274 {
  275     if (c >= '0' && c <= '9')
  276     return c - '0';
  277     if (c >= 'a' && c <= 'f')
  278     return c - 'a' + 10;
  279     if (c >= 'A' && c <= 'F')
  280     return c - 'A' + 10;
  281     return -1;
  282 }
  283 
  284 /*
  285  * Check if the given string is nonnull/nonempty.  If so, return a pointer
  286  * to the beginning of its content, otherwise return null.
  287  */
  288 String
  289 x_nonempty(String s)
  290 {
  291     if (s != 0) {
  292     if (*s == '\0') {
  293         s = 0;
  294     } else {
  295         s = x_skip_blanks(s);
  296         if (*s == '\0')
  297         s = 0;
  298     }
  299     }
  300     return s;
  301 }
  302 
  303 String
  304 x_skip_blanks(String s)
  305 {
  306     while (IsSpace(CharOf(*s)))
  307     ++s;
  308     return s;
  309 }
  310 
  311 String
  312 x_skip_nonblanks(String s)
  313 {
  314     while (*s != '\0' && !IsSpace(CharOf(*s)))
  315     ++s;
  316     return s;
  317 }
  318 
  319 static const char *
  320 skip_blanks(const char *s)
  321 {
  322     while (IsSpace(CharOf(*s)))
  323     ++s;
  324     return s;
  325 }
  326 
  327 /*
  328  * Split a command-string into an argv[]-style array.
  329  */
  330 char **
  331 x_splitargs(const char *command)
  332 {
  333     char **result = 0;
  334 
  335     if (command != 0) {
  336     const char *first = skip_blanks(command);
  337     char *blob = x_strdup(first);
  338 
  339     if (blob != 0) {
  340         int pass;
  341 
  342         for (pass = 0; pass < 2; ++pass) {
  343         int state;
  344         size_t count;
  345         size_t n;
  346 
  347         for (n = count = 0, state = 0; first[n] != '\0'; ++n) {
  348 
  349             switch (state) {
  350             case 0:
  351             if (!IsSpace(CharOf(first[n]))) {
  352                 state = 1;
  353                 if (pass)
  354                 result[count] = blob + n;
  355                 ++count;
  356             } else {
  357                 blob[n] = '\0';
  358             }
  359             break;
  360             case 1:
  361             if (IsSpace(CharOf(first[n]))) {
  362                 blob[n] = '\0';
  363                 state = 0;
  364             }
  365             break;
  366             }
  367         }
  368         if (!pass) {
  369             result = TypeCallocN(char *, count + 1);
  370             if (!result) {
  371             free(blob);
  372             break;
  373             }
  374         }
  375         }
  376     }
  377     } else {
  378     result = TypeCalloc(char *);
  379     }
  380     return result;
  381 }
  382 
  383 /*
  384  * Free storage allocated by x_splitargs().
  385  */
  386 void
  387 x_freeargs(char **argv)
  388 {
  389     if (argv != 0) {
  390     free(*argv);
  391     free(argv);
  392     }
  393 }
  394 
  395 int
  396 x_strcasecmp(const char *s1, const char *s2)
  397 {
  398     size_t len1 = (s1 != NULL) ? strlen(s1) : 0;
  399     size_t len2 = (s2 != NULL) ? strlen(s2) : 0;
  400 
  401     return ((len1 != len2)
  402         ? 1
  403         : x_strncasecmp(s1, s2, (unsigned) len1));
  404 }
  405 
  406 int
  407 x_strncasecmp(const char *s1, const char *s2, unsigned n)
  408 {
  409     int result = 0;
  410 
  411     if (s1 != NULL && s2 != NULL) {
  412     while (n-- != 0) {
  413         char c1 = x_toupper(*s1);
  414         char c2 = x_toupper(*s2);
  415         if (c1 != c2) {
  416         result = 1;
  417         break;
  418         } else if (c1 == 0) {
  419         break;
  420         }
  421         s1++;
  422         s2++;
  423     }
  424     } else if (s1 == NULL && s2 != NULL) {
  425     result = 1;
  426     } else if (s1 != NULL && s2 == NULL) {
  427     result = 1;
  428     }
  429 
  430     return result;
  431 }
  432 
  433 /*
  434  * Allocates a copy of a string
  435  */
  436 char *
  437 x_strdup(const char *s)
  438 {
  439     char *result = 0;
  440 
  441     if (s != 0) {
  442     char *t = malloc(strlen(s) + 5);
  443     if (t != 0) {
  444         strcpy(t, s);
  445     }
  446     result = t;
  447     }
  448     return result;
  449 }
  450 
  451 /*
  452  * Returns a pointer to the first occurrence of s2 in s1,
  453  * or NULL if there are none.
  454  */
  455 char *
  456 x_strindex(char *s1, const char *s2)
  457 {
  458     char *s3;
  459     size_t s2len = strlen(s2);
  460 
  461     while ((s3 = (strchr) (s1, *s2)) != NULL) {
  462     if (strncmp(s3, s2, s2len) == 0)
  463         return (s3);
  464     s1 = ++s3;
  465     }
  466     return (NULL);
  467 }
  468 
  469 /*
  470  * Trims leading/trailing spaces from a copy of the string.
  471  */
  472 char *
  473 x_strtrim(const char *source)
  474 {
  475     char *result;
  476 
  477     if (IsEmpty(source)) {
  478     result = x_strdup("");
  479     } else {
  480     char *t = x_strdup(source);
  481     if (t != 0) {
  482         char *s = t;
  483         char *d = s;
  484         while (IsSpace(CharOf(*s)))
  485         ++s;
  486         while ((*d++ = *s++) != '\0') {
  487         ;
  488         }
  489         if (*t != '\0') {
  490         s = t + strlen(t);
  491         while (s != t && IsSpace(CharOf(s[-1]))) {
  492             *--s = '\0';
  493         }
  494         }
  495     }
  496     result = t;
  497     }
  498     return result;
  499 }
  500 
  501 /*
  502  * Trims trailing whitespace from a copy of the string.
  503  */
  504 char *
  505 x_strrtrim(const char *source)
  506 {
  507     char *result;
  508 
  509     if (IsEmpty(source)) {
  510     result = x_strdup("");
  511     } else {
  512     char *t = x_strdup(source);
  513     if (t != 0) {
  514         if (*t != '\0') {
  515         char *s = t + strlen(t);
  516         while (s != t && IsSpace(CharOf(s[-1]))) {
  517             *--s = '\0';
  518         }
  519         }
  520     }
  521     result = t;
  522     }
  523     return result;
  524 }
  525 
  526 /*
  527  * Avoid using system locale for upper/lowercase conversion, since there are
  528  * a few locales where toupper(tolower(c)) != c.
  529  */
  530 char
  531 x_toupper(int ch)
  532 {
  533     static char table[256];
  534     char result = table[CharOf(ch)];
  535 
  536     if (result == '\0') {
  537     unsigned n;
  538     static const char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  539 
  540     for (n = 0; n < sizeof(table); ++n) {
  541         table[n] = (char) n;
  542     }
  543     for (n = 0; s[n] != '\0'; ++n) {
  544         table[CharOf(s[n])] = s[n % 26];
  545     }
  546     result = table[CharOf(ch)];
  547     }
  548 
  549     return result;
  550 }
  551 
  552 /*
  553  * Match strings ignoring case and allowing glob-like '*' and '?'
  554  */
  555 int
  556 x_wildstrcmp(const char *pattern, const char *actual)
  557 {
  558     int result = 0;
  559 
  560     while (*pattern && *actual) {
  561     char c1 = x_toupper(*pattern);
  562     char c2 = x_toupper(*actual);
  563 
  564     if (c1 == '*') {
  565         Boolean found = False;
  566         pattern++;
  567         while (*actual != '\0') {
  568         if (!x_wildstrcmp(pattern, actual++)) {
  569             found = True;
  570             break;
  571         }
  572         }
  573         if (!found) {
  574         result = 1;
  575         break;
  576         }
  577     } else if (c1 == '?') {
  578         ++pattern;
  579         ++actual;
  580     } else if ((result = (c1 != c2)) == 0) {
  581         ++pattern;
  582         ++actual;
  583     } else {
  584         break;
  585     }
  586     }
  587     return result;
  588 }