"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 }