1 /* strings.c -- misc string manipulation function */
2 
3 /*
4  * This file is part of CliFM
5  *
6  * Copyright (C) 2016-2021, L. Abramovich <johndoe.arch@outlook.com>
7  * All rights reserved.
8 
9  * CliFM is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * CliFM is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1301, USA.
23 */
24 
25 #include "helpers.h"
26 
27 #ifdef __HAIKU__
28 #include <stdint.h>
29 #endif
30 #include <glob.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <time.h>
35 #include <wchar.h>
36 #if !defined(__HAIKU__) && !defined(__OpenBSD__)
37 #include <wordexp.h>
38 #endif
39 
40 #include "aux.h"
41 #include "checks.h"
42 #include "exec.h"
43 #include "navigation.h"
44 #include "readline.h"
45 
46 #define CMD_LEN_MAX (PATH_MAX + ((NAME_MAX + 1) << 1))
47 char len_buf[CMD_LEN_MAX] __attribute__((aligned));
48 
49 /* states: S_N: normal, S_I: comparing integral part, S_F: comparing
50            fractionnal parts, S_Z: idem but with leading Zeroes only */
51 #define S_N 0x0
52 #define S_I 0x3
53 #define S_F 0x6
54 #define S_Z 0x9
55 
56 /* result_type: VCMP: return diff; VLEN: compare using len_diff/diff */
57 #define VCMP 2
58 #define VLEN 3
59 
60 #define MAX_STR_SZ 4096
61 
62 
63 /* Just a strlen that sets a read limit in case of non-null terminated
64  * string */
65 size_t
xstrnlen(const char * restrict s)66 xstrnlen(const char *restrict s)
67 {
68 	return (size_t)((char *)memchr(s, '\0', MAX_STR_SZ) - s);
69 }
70 
71 /* Taken from NNN's source code: very clever. Copy SRC into DST
72  * and return the string size all at once */
73 size_t
xstrsncpy(char * restrict dst,const char * restrict src,size_t n)74 xstrsncpy(char *restrict dst, const char *restrict src, size_t n)
75 {
76 	n++;
77 	char *end = memccpy(dst, src, '\0', n);
78 	if (!end) {
79 		dst[n - 1] = '\0';
80 		end = dst + n;
81 	}
82 
83 	return (size_t)(end - dst - 1);
84 }
85 
86 /* strverscmp() is a GNU extension, and as such not available on some systems
87  * This function is a modified version of the GLIBC and uClibc strverscmp()
88  * taken from here:
89  * https://elixir.bootlin.com/uclibc-ng/latest/source/libc/string/strverscmp.c
90  */
91 
92 /* Compare S1 and S2 as strings holding indices/version numbers,
93    returning less than, equal to or greater than zero if S1 is less than,
94    equal to or greater than S2 (for more info, see the texinfo doc).
95 */
96 int
xstrverscmp(const char * s1,const char * s2)97 xstrverscmp(const char *s1, const char *s2)
98 {
99 	if ((*s1 & 0xc0) == 0xc0 || (*s2 & 0xc0) == 0xc0)
100 		return strcoll(s1, s2);
101 
102 	const unsigned char *p1 = (const unsigned char *)s1;
103 	const unsigned char *p2 = (const unsigned char *)s2;
104 
105 	/* Symbol(s)    0       [1-9]   others
106 	 Transition   (10) 0  (01) d  (00) x   */
107 	static const uint8_t next_state[] = {
108 	/* state    x    d    0  */
109 	/* S_N */  S_N, S_I, S_Z,
110 	/* S_I */  S_N, S_I, S_I,
111 	/* S_F */  S_N, S_F, S_F,
112 	/* S_Z */  S_N, S_F, S_Z
113 	};
114 
115 	static const int8_t result_type[] __attribute__ ((aligned)) = {
116 		/* state   x/x  x/d  x/0  d/x  d/d  d/0  0/x  0/d  0/0  */
117 		/* S_N */  VCMP, VCMP, VCMP, VCMP, VLEN, VCMP, VCMP, VCMP, VCMP,
118 		/* S_I */  VCMP,   -1,   -1,    1, VLEN, VLEN,    1, VLEN, VLEN,
119 		/* S_F */  VCMP, VCMP, VCMP, VCMP, VCMP, VCMP, VCMP, VCMP, VCMP,
120 		/* S_Z */  VCMP,    1,    1,   -1, VCMP, VCMP,   -1, VCMP, VCMP
121 	};
122 
123 	unsigned char c1, c2;
124 	int state, diff;
125 
126 	if (p1 == p2)
127 		return 0;
128 
129 	if (!case_sensitive) {
130 		c1 = TOUPPER(*p1);
131 		++p1;
132 		c2 = TOUPPER(*p2);
133 		++p2;
134 	} else {
135 		c1 = *p1++;
136 		c2 = *p2++;
137 	}
138 
139 	/* Hint: '0' is a digit too.  */
140 	state = S_N + ((c1 == '0') + (_ISDIGIT(c1) != 0));
141 
142 	while ((diff = c1 - c2) == 0) {
143 		if (c1 == '\0')
144 			return diff;
145 
146 		state = next_state[state];
147 		if (!case_sensitive) {
148 			c1 = TOUPPER(*p1);
149 			++p1;
150 			c2 = TOUPPER(*p2);
151 			++p2;
152 		} else {
153 			c1 = *p1++;
154 			c2 = *p2++;
155 		}
156 		state += (c1 == '0') + (_ISDIGIT(c1) != 0);
157 	}
158 
159 	state = result_type[state * 3 + (((c2 == '0') + (_ISDIGIT(c2) != 0)))];
160 
161 	switch (state) {
162 	case VCMP: return diff;
163 	case VLEN:
164 		while (_ISDIGIT(*p1++))
165 			if (!_ISDIGIT(*p2++))
166 				return 1;
167 
168 		return _ISDIGIT(*p2) ? -1 : diff;
169 
170 	default: return state;
171 	}
172 }
173 
174 /* A strlen implementation able to handle wide chars */
175 size_t
wc_xstrlen(const char * restrict str)176 wc_xstrlen(const char *restrict str)
177 {
178 	size_t len, _len;
179 	wchar_t *const wbuf = (wchar_t *)len_buf;
180 
181 	/* Convert multi-byte to wide char */
182 	_len = mbstowcs(wbuf, str, NAME_MAX);
183 	int p = wcswidth(wbuf, _len);
184 	if (p != -1)
185 		len = (size_t)p;
186 	else
187 		len = 0;
188 
189 	return len;
190 }
191 
192 /* Truncate an UTF-8 string at width N. Returns the difference beetween
193  * N and the point at which STR was actually trimmed (this difference
194  * should be added to STR as spaces to equate N and get a correct length)
195  * Since a wide char could take two o more columns to be draw, and since
196  * you might want to trim the name in the middle of a wide char, this
197  * function won't store the last wide char to avoid taking more columns
198  * than N. In this case, the programmer should take care of filling the
199  * empty spaces (usually no more than one) herself */
200 int
u8truncstr(char * restrict str,size_t n)201 u8truncstr(char *restrict str, size_t n)
202 {
203 	int len = 0;
204 	wchar_t buf[PATH_MAX] = {0};
205 	if (mbstowcs(buf, str, PATH_MAX) == (size_t)-1)
206 		return 0;
207 
208 	int i = 0;
209 	for (; buf[i]; i++) {
210 		int l = wcwidth(buf[i]);
211 		if (len + l > (int)n) {
212 			buf[i] = L'\0';
213 			break;
214 		}
215 		len += l;
216 	}
217 
218 	wcscpy((wchar_t *)str, buf);
219 	return (int)n - len;
220 }
221 
222 /* Returns the index of the first appearance of c in str, if any, and
223  * -1 if c was not found or if no str. NOTE: Same thing as strchr(),
224  * except that returns an index, not a pointer */
225 int
strcntchr(const char * str,const char c)226 strcntchr(const char *str, const char c)
227 {
228 	if (!str)
229 		return -1;
230 
231 	register int i = 0;
232 
233 	while (*str) {
234 		if (*str == c)
235 			return i;
236 		i++;
237 		str++;
238 	}
239 
240 	return -1;
241 }
242 
243 /* Returns the index of the last appearance of c in str, if any, and
244  * -1 if c was not found or if no str */
245 int
strcntchrlst(const char * str,const char c)246 strcntchrlst(const char *str, const char c)
247 {
248 	if (!str)
249 		return -1;
250 
251 	register int i = 0;
252 
253 	int p = -1;
254 	while (*str) {
255 		if (*str == c)
256 			p = i;
257 		i++;
258 		str++;
259 	}
260 
261 	return p;
262 }
263 
264 /* Returns the string after the last appearance of a given char, or
265  * NULL if no match */
266 char *
straftlst(char * str,const char c)267 straftlst(char *str, const char c)
268 {
269 	if (!str || !*str || !c)
270 		return (char *)NULL;
271 
272 	char *p = str, *q = (char *)NULL;
273 
274 	while (*p) {
275 		if (*p == c)
276 			q = p;
277 		p++;
278 	}
279 
280 	if (!q || !*(q + 1))
281 		return (char *)NULL;
282 
283 	char *buf = (char *)malloc(strlen(q + 1) + 1);
284 
285 	if (!buf)
286 		return (char *)NULL;
287 
288 	strcpy(buf, q + 1);
289 	return buf;
290 }
291 
292 /* Get substring in STR before the last appearance of C. Returns
293  * substring  if C is found and NULL if not (or if C was the first
294  * char in STR). */
295 char *
strbfrlst(char * str,const char c)296 strbfrlst(char *str, const char c)
297 {
298 	if (!str || !*str || !c)
299 		return (char *)NULL;
300 
301 	char *p = str, *q = (char *)NULL;
302 	while (*p) {
303 		if (*p == c)
304 			q = p;
305 		p++;
306 	}
307 
308 	if (!q || q == str)
309 		return (char *)NULL;
310 
311 	*q = '\0';
312 
313 	char *buf = (char *)malloc((size_t)(q - str + 1));
314 	if (!buf) {
315 		*q = c;
316 		return (char *)NULL;
317 	}
318 
319 	strcpy(buf, str);
320 	*q = c;
321 	return buf;
322 }
323 
324 /* Returns the string between first ocurrence of A and the first
325  * ocurrence of B in STR, or NULL if: there is nothing between A and
326  * B, or A and/or B are not found */
327 char *
strbtw(char * str,const char a,const char b)328 strbtw(char *str, const char a, const char b)
329 {
330 	if (!str || !*str || !a || !b)
331 		return (char *)NULL;
332 
333 	char *p = str, *pa = (char *)NULL, *pb = (char *)NULL;
334 	while (*p) {
335 		if (!pa) {
336 			if (*p == a)
337 				pa = p;
338 		} else if (*p == b) {
339 			pb = p;
340 			break;
341 		}
342 		p++;
343 	}
344 
345 	if (!pb)
346 		return (char *)NULL;
347 
348 	*pb = '\0';
349 
350 	char *buf = (char *)malloc((size_t)(pb - pa));
351 
352 	if (!buf) {
353 		*pb = b;
354 		return (char *)NULL;
355 	}
356 
357 	strcpy(buf, pa + 1);
358 	*pb = b;
359 	return buf;
360 }
361 
362 /* Replace the first occurrence of NEEDLE in HAYSTACK by REP */
363 char *
replace_substr(char * haystack,char * needle,char * rep)364 replace_substr(char *haystack, char *needle, char *rep)
365 {
366 	if (!haystack || !*haystack || !needle || !*needle || !rep)
367 		return (char *)NULL;
368 
369 	char *ret = strstr(haystack, needle);
370 	if (!ret)
371 		return (char *)NULL;
372 
373 	char *needle_end = ret + strlen(needle);
374 	*ret = '\0';
375 
376 	if (*needle_end) {
377 		size_t rem_len = strlen(needle_end);
378 		char *rem = (char *)xnmalloc(rem_len + 1, sizeof(char));
379 		strcpy(rem, needle_end);
380 
381 		char *new_str = (char *)xnmalloc(strlen(haystack) + strlen(rep)
382 						+ rem_len + 1, sizeof(char));
383 		strcpy(new_str, haystack);
384 		strcat(new_str, rep);
385 		strcat(new_str, rem);
386 		free(rem);
387 		return new_str;
388 	}
389 
390 	char *new_str = (char *)xnmalloc(strlen(haystack) + strlen(rep)
391 					+ 1, sizeof(char));
392 	strcpy(new_str, haystack);
393 	strcat(new_str, rep);
394 	return new_str;
395 }
396 
397 /* Generate a random string of LEN bytes using characters from CHARSET */
398 char *
gen_rand_str(size_t len)399 gen_rand_str(size_t len)
400 {
401 	char charset[] = "0123456789#%-_"
402 			 "abcdefghijklmnopqrstuvwxyz"
403 			 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
404 
405 	srand((unsigned int)time(NULL));
406 
407 	char *str = (char *)malloc((len + 1) * sizeof(char));
408 	char *p = str;
409 
410 	if (!p) {
411 		fprintf(stderr, "Error allocating %zu bytes\n", len);
412 		return (char *)NULL;
413 	}
414 
415 	while (len--) {
416 		int i = rand() % (int)(sizeof(charset) - 1);
417 		*p++ = charset[i];
418 	}
419 
420 	*p = '\0';
421 	return str;
422 }
423 
424 /* Removes end of line char and quotes (single and double) from STR.
425  * Returns a pointer to the modified STR if the result is non-blank
426  * or NULL */
427 char *
remove_quotes(char * str)428 remove_quotes(char *str)
429 {
430 	if (!str || !*str)
431 		return (char *)NULL;
432 
433 	char *p = str;
434 	size_t len = strlen(p);
435 
436 	if (len > 0 && p[len - 1] == '\n') {
437 		p[len - 1] = '\0';
438 		len--;
439 	}
440 
441 	if (len > 0 && (p[len - 1] == '\'' || p[len - 1] == '"'))
442 		p[len - 1] = '\0';
443 
444 	if (*p == '\'' || *p == '"')
445 		p++;
446 
447 	if (!*p)
448 		return (char *)NULL;
449 
450 	char *q = p;
451 	int blank = 1;
452 
453 	while (*q) {
454 		if (*q != ' ' && *q != '\n' && *q != '\t') {
455 			blank = 0;
456 			break;
457 		}
458 		q++;
459 	}
460 
461 	if (!blank)
462 		return p;
463 	return (char *)NULL;
464 }
465 
466 /* This function takes a string as argument and split it into substrings
467  * taking tab, new line char, and space as word delimiters, except when
468  * they are preceded by a quote char (single or double quotes) or in
469  * case of command substitution ($(cmd) or `cmd`), in which case
470  * eveything after the corresponding closing char is taken as one single
471  * string. It also escapes spaecial chars. It returns an array of
472  * splitted strings (without leading and terminating spaces) or NULL if
473  * str is NULL or if no substring was found, i.e., if str contains
474  * only spaces. */
475 char **
split_str(const char * str)476 split_str(const char *str)
477 {
478 	if (!str)
479 		return (char **)NULL;
480 
481 	size_t buf_len = 0, words = 0, str_len = 0;
482 	char *buf = (char *)NULL;
483 	buf = (char *)xnmalloc(1, sizeof(char));
484 	int quote = 0, close = 0;
485 	char **substr = (char **)NULL;
486 
487 	while (*str) {
488 		switch (*str) {
489 		/* Command substitution */
490 		case '$': /* fallthrough */
491 		case '`':
492 			/* Define the closing char: If "$(" then ')', else '`' */
493 			if (*str == '$') {
494 				/* If escaped, it has no special meaning */
495 				if ((str_len && *(str - 1) == '\\') || *(str + 1) != '(') {
496 					buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *));
497 					buf[buf_len++] = *str;
498 					break;
499 				} else {
500 					close = ')';
501 				}
502 			} else {
503 				/* If escaped, it has no special meaning */
504 				if (str_len && *(str - 1) == '\\') {
505 					buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *));
506 					buf[buf_len++] = *str;
507 					break;
508 				} else {
509 					/* If '`' advance one char. Otherwise the while
510 					 * below will stop at first char, which is not
511 					 * what we want */
512 					close = *str;
513 					str++;
514 					buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *));
515 					buf[buf_len++] = '`';
516 				}
517 			}
518 
519 			/* Copy everything until null byte or closing char */
520 			while (*str && *str != close) {
521 				buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *));
522 				buf[buf_len++] = *(str++);
523 			}
524 
525 			/* If the while loop stopped with a null byte, there was
526 			 * no ending close (either ')' or '`')*/
527 			if (!*str) {
528 				fprintf(stderr, _("%s: Missing '%c'\n"), PROGRAM_NAME,
529 				    close);
530 
531 				free(buf);
532 				buf = (char *)NULL;
533 				int i = (int)words;
534 
535 				while (--i >= 0)
536 					free(substr[i]);
537 				free(substr);
538 
539 				return (char **)NULL;
540 			}
541 
542 			/* Copy the closing char and add an space: this function
543 			 * takes space as word breaking char, so that everything
544 			 * in the buffer will be copied as one single word */
545 			buf = (char *)xrealloc(buf, (buf_len + 2) * sizeof(char *));
546 			buf[buf_len++] = *str;
547 			buf[buf_len] = ' ';
548 
549 			break;
550 
551 		case '\'': /* fallthrough */
552 		case '"':
553 			/* If the quote is escaped, it has no special meaning */
554 			if (str_len && *(str - 1) == '\\') {
555 				buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *));
556 				buf[buf_len++] = *str;
557 				break;
558 			}
559 
560 			/* If not escaped, move on to the next char */
561 			quote = *str;
562 			str++;
563 
564 			/* Copy into the buffer whatever is after the first quote
565 			 * up to the last quote or NULL */
566 			while (*str && *str != quote) {
567 				/* If char has special meaning, escape it */
568 				if (is_quote_char(*str)) {
569 					buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *));
570 					buf[buf_len++] = '\\';
571 				}
572 
573 				buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *));
574 				buf[buf_len++] = *(str++);
575 			}
576 
577 			/* The above while breaks with NULL or quote, so that if
578 			 * *str is a null byte there was not ending quote */
579 			if (!*str) {
580 				fprintf(stderr, _("%s: Missing '%c'\n"), PROGRAM_NAME, quote);
581 				/* Free the current buffer and whatever was already
582 				 * allocated */
583 				free(buf);
584 				buf = (char *)NULL;
585 				int i = (int)words;
586 
587 				while (--i >= 0)
588 					free(substr[i]);
589 				free(substr);
590 				return (char **)NULL;
591 			}
592 			break;
593 
594 		/* TAB, new line char, and space are taken as word breaking
595 		 * characters */
596 		case '\t':
597 		case '\n':
598 		case ' ':
599 			/* If escaped, just copy it into the buffer */
600 			if (str_len && *(str - 1) == '\\') {
601 				buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *));
602 				buf[buf_len++] = *str;
603 			} else {
604 				/* If not escaped, break the string */
605 				/* Add a terminating null byte to the buffer, and, if
606 				 * not empty, dump the buffer into the substrings
607 				 * array */
608 				buf[buf_len] = '\0';
609 
610 				if (buf_len > 0) {
611 					substr = (char **)xrealloc(substr, (words + 1) * sizeof(char *));
612 					substr[words] = savestring(buf, buf_len);
613 					words++;
614 				}
615 
616 				/* Clear te buffer to get a new string */
617 				memset(buf, '\0', buf_len);
618 				buf_len = 0;
619 			}
620 			break;
621 
622 		/* If neither a quote nor a breaking word char nor command
623 		 * substitution, just dump it into the buffer */
624 		default:
625 			buf = (char *)xrealloc(buf, (buf_len + 1) * sizeof(char *));
626 			buf[buf_len++] = *str;
627 			break;
628 		}
629 
630 		str++;
631 		str_len++;
632 	}
633 
634 	/* The while loop stops when the null byte is reached, so that the
635 	 * last substring is not printed, but still stored in the buffer.
636 	 * Therefore, we need to add it, if not empty, to our subtrings
637 	 * array */
638 	buf[buf_len] = '\0';
639 
640 	if (buf_len > 0) {
641 		if (!words)
642 			substr = (char **)xcalloc(words + 1, sizeof(char *));
643 		else
644 			substr = (char **)xrealloc(substr, (words + 1) * sizeof(char *));
645 
646 		substr[words] = savestring(buf, buf_len);
647 		words++;
648 	}
649 
650 	free(buf);
651 	buf = (char *)NULL;
652 
653 	if (words) {
654 		/* Add a final null string to the array */
655 		substr = (char **)xrealloc(substr, (words + 1) * sizeof(char *));
656 		substr[words] = (char *)NULL;
657 
658 		args_n = words - 1;
659 		return substr;
660 	} else {
661 		args_n = 0; /* Just in case, but I think it's not needed */
662 		return (char **)NULL;
663 	}
664 }
665 
666 /* Return 1 if STR contains only numbers of a range of numbers, and zero
667  * if not */
668 static int
check_fused_param(const char * str)669 check_fused_param(const char *str)
670 {
671 	char *p = (char *)str;
672 	size_t c = 0, i = 0;
673 	int ok = 1;
674 
675 	while (*p) {
676 		if (i && *p == '-' && *(p - 1) >= '0' && *(p - 1) <= '9'
677 		&& *(p + 1) >= '1' && *(p + 1) <= '9') {
678 			c++;
679 		} else if (*p == ' ') {
680 			break;
681 		} else if (*p < '0' || *p > '9') {
682 			ok = 0;
683 			break;
684 		}
685 		p++;
686 		i++;
687 	}
688 
689 	if (ok && c <= 1)
690 		return 1;
691 	return 0;
692 }
693 
694 /* Check CMD against a list of internal commands taking ELN's or numbers
695  * as parameters. Used by split_fusedcmd() */
696 int
is_internal_f(const char * restrict cmd)697 is_internal_f(const char *restrict cmd)
698 {
699 	const char *int_cmds[] = {
700 	    "ac", "ad",
701 		"bb", "bleach",
702 	    "bm", "bookmarks",
703 	    "br", "bulk",
704 	    "c", "cp",
705 	    "cd",
706 		"d", "dup",
707 	    "exp",
708 	    "l", "ln", "le",
709 	    "m", "mv",
710 	    "md", "mkdir",
711 	    "mf",
712 	    "n", "new",
713 	    "o", "open", "ow",
714 	    "p", "pp", "pr", "prop",
715 		"paste",
716 	    "pin",
717 	    "r", "rm",
718 	    "s", "sel",
719 	    "st", "sort",
720 	    "t", "tr", "trash",
721 	    "te",
722 	    "unlink",
723 	    "ws",
724 	    NULL};
725 
726 	int i = (int)(sizeof(int_cmds) / sizeof(char *)) - 1;
727 
728 	while (--i >= 0) {
729 		if (*cmd == *int_cmds[i] && strcmp(cmd, int_cmds[i]) == 0)
730 			return 1;
731 	}
732 
733 	return 0;
734 }
735 
736 static char *
split_fusedcmd(char * str)737 split_fusedcmd(char *str)
738 {
739 	if (!str || !*str || *str == ';' || *str == ':' || *str == '\\')
740 		return (char *)NULL;
741 
742 	char *space = strchr(str, ' ');
743 	char *slash = strchr(str, '/');
744 
745 	if (!space && slash) /* If "/some/path/" */
746 		return (char *)NULL;
747 
748 	if (space && slash && slash < space) /* If "/some/string something" */
749 		return (char *)NULL;
750 
751 	/* The buffer size is the double of STR, just in case each subtr
752 	 * needs to be splitted */
753 	char *buf = (char *)xnmalloc(((strlen(str) * 2) + 2), sizeof(char));
754 
755 	size_t c = 0;
756 	char *p = str, *pp = str, *b = buf;
757 	size_t words = 1;
758 	while (*p) {
759 		switch(*p) {
760 		case ' ': /* We only allow splitting for first command word */
761 			if (c && *(p - 1) != ' ' && *(p - 1) != '|'
762 			&& *(p - 1) != '&' && *(p - 1) != ';')
763 				words++;
764 			if (*(p + 1))
765 				pp = p + 1;
766 			break;
767 		case '&': // fallthrough
768 		case '|': // fallthrough
769 		case ';':
770 			words = 1;
771 			if (*(p + 1))
772 				pp = p + 1;
773 			break;
774 		default: break;
775 		}
776 		if (words == 1 && c && *p >= '0' && *p <= '9'
777 		&& (*(p - 1) < '0' || *(p - 1) > '9')) {
778 			if (check_fused_param(p)) {
779 				char t = *p;
780 				*p = '\0';
781 				if (is_internal_f(pp))
782 					*(b++) = ' ';
783 				*p = t;
784 			}
785 		}
786 		*(b++) = *(p++);
787 		c++;
788 	}
789 
790 	*b = '\0';
791 
792 	/* Readjust the buffer size */
793 	size_t len = strlen(buf);
794 	buf = (char *)xrealloc(buf, (len + 1) * sizeof(char));
795 	return buf;
796 }
797 
798 static int
check_shell_functions(char * str)799 check_shell_functions(char *str)
800 {
801 	if (!str || !*str)
802 		return 0;
803 
804 	if (!int_vars) {
805 		char *s = strchr(str, ' ');
806 		char *e = strchr(str, '=');
807 		if (!s && e)
808 			return 1;
809 		if (s && e && e < s)
810 			return 1;
811 	}
812 
813 /*	char **b = (char **)NULL;
814 
815 	switch(shell) {
816 	case SHELL_NONE: return 0;
817 	case SHELL_BASH: b = bash_builtins; break;
818 	case SHELL_DASH: b = dash_builtins; break;
819 	case SHELL_KSH: b = ksh_builtins; break;
820 	case SHELL_TCSH: b = tcsh_builtins; break;
821 	case SHELL_ZSH: b = zsh_builtins; break;
822 	default: return 0;
823 	} */
824 
825 	char *funcs[] = {
826 		"for ", "for(",
827 		"do ", "do(",
828 		"while ", "while(",
829 		"until ", "until(",
830 		"if ", "if(",
831 		"[ ", "[[ ", "test ",
832 		"case ", "case(",
833 		"echo ", "printf ",
834 		"declare ",
835 		"(( ",
836 		"set ",
837 		"source ", ". ",
838 		NULL
839 	};
840 
841 	size_t i;
842 	for (i = 0; funcs[i]; i++) {
843 		size_t f_len = strlen(funcs[i]);
844 		if (*str == *funcs[i] && strncmp(str, funcs[i], f_len) == 0)
845 			return 1;
846 	}
847 
848 	return 0;
849 }
850 
851 /*
852  * This function is one of the keys of CliFM. It will perform a series of
853  * actions:
854  * 1) Take the string stored by readline and get its substrings without
855  * spaces.
856  * 2) In case of user defined variable (var=value), it will pass the
857  * whole string to exec_cmd(), which will take care of storing the
858  * variable;
859  * 3) If the input string begins with ';' or ':' the whole string is
860  * send to exec_cmd(), where it will be directly executed by the system
861  * shell (via launch_execle()) to prevent all of the expansions made
862  * here.
863  * 4) The following expansions (especific to CLiFM) are performed here:
864  * ELN's, "sel" keyword, ranges of numbers (ELN's), pinned dir and
865  * bookmark names, and, for internal commands only, tilde, braces,
866  * wildcards, command and paramenter substitution, and regex expansion
867  * are performed here as well.
868  * These expansions are the most import part of this function.
869  */
870 
871 /* NOTE: Though file names could consist of everything except of slash
872  * and null characters, POSIX.1 recommends restricting file names to
873  * consist of the following characters: letters (a-z, A-Z), numbers
874  * (0-9), period (.), dash (-), and underscore ( _ ).
875 
876  * NOTE 2: There is no any need to pass anything to this function, since
877  * the input string I need here is already in the readline buffer. So,
878  * instead of taking the buffer from a function parameter (str) I could
879  * simply use rl_line_buffer. However, since I use this function to
880  * parse other strings, like history lines, I need to keep the str
881  * argument */
882 
883 /* This shit is HUGE! Almost 1000 LOC and a lot of indentation! */
884 char **
parse_input_str(char * str)885 parse_input_str(char *str)
886 {
887 	register size_t i = 0;
888 	int fusedcmd_ok = 0;
889 
890 	/** ###################### */
891 	/* Before splitting 'CMDNUM' into 'CMD NUM', make sure CMDNUM is not
892 	 * a cmd in PATH (for example, md5sum) */
893 	if (digit_found(str) && !is_bin_cmd(str)) {
894 		char *p = split_fusedcmd(str);
895 		if (p) {
896 			fusedcmd_ok = 1;
897 			str = p;
898 			p = (char *)NULL;
899 		}
900 	}
901 	/** ###################### */
902 
903 			/* ########################################
904 			* #    0) CHECK FOR SPECIAL FUNCTIONS    #
905 			* ########################################*/
906 
907 	int chaining = 0, cond_cmd = 0, send_shell = 0;
908 
909 				/* ###########################
910 				 * #  0.a) RUN AS EXTERNAL   #
911 				 * ###########################*/
912 
913 	/* If invoking a command via ';' or ':' set the send_shell flag to
914 	 * true and send the whole string to exec_cmd(), in which case no
915 	 * expansion is made: the command is send to the system shell as
916 	 * is. */
917 	if (*str == ';' || *str == ':')
918 		send_shell = 1;
919 	else if (check_shell_functions(str))
920 		send_shell = 1;
921 
922 	if (!send_shell) {
923 		for (i = 0; str[i]; i++) {
924 
925 				/* ##################################
926 				 * #   0.b) CONDITIONAL EXECUTION   #
927 				 * ##################################*/
928 
929 			/* Check for chained commands (cmd1;cmd2) */
930 			if (!chaining && str[i] == ';' && i > 0 && str[i - 1] != '\\')
931 				chaining = 1;
932 
933 			/* Check for conditional execution (cmd1 && cmd 2)*/
934 			if (!cond_cmd && str[i] == '&' && i > 0 && str[i - 1] != '\\'
935 			&& str[i + 1] && str[i + 1] == '&')
936 				cond_cmd = 1;
937 
938 				/* ##################################
939 				 * #   0.c) USER DEFINED VARIABLE   #
940 				 * ##################################*/
941 
942 			/* If user defined variable send the whole string to
943 			 * exec_cmd(), which will take care of storing the
944 			 * variable. */
945 			if (!(flags & IS_USRVAR_DEF) && str[i] == '=' && i > 0
946 			&& str[i - 1] != '\\' && str[0] != '=') {
947 				/* Remove leading spaces. This: '   a="test"' should be
948 				 * taken as a valid variable declaration */
949 				char *p = str;
950 				while (*p == ' ' || *p == '\t')
951 					p++;
952 
953 				/* If first non-space is a number, it's not a variable
954 				 * name */
955 				if (!_ISDIGIT(*p)) {
956 					int space_found = 0;
957 					/* If there are no spaces before '=', take it as a
958 					 * variable. This check is done in order to avoid
959 					 * taking as a variable things like:
960 					 * 'ls -color=auto' */
961 					while (*p != '=') {
962 						if (*(p++) == ' ')
963 							space_found = 1;
964 					}
965 
966 					if (!space_found)
967 						flags |= IS_USRVAR_DEF;
968 				}
969 
970 				p = (char *)NULL;
971 			}
972 		}
973 	}
974 
975 	/* If chained commands, check each of them. If at least one of them
976 	 * is internal, take care of the job (the system shell does not know
977 	 * our internal commands and therefore cannot execute them); else,
978 	 * if no internal command is found, let it to the system shell */
979 	if (chaining || cond_cmd) {
980 		/* User defined variables are always internal, so that there is
981 		 * no need to check whatever else is in the command string */
982 		if (flags & IS_USRVAR_DEF) {
983 			exec_chained_cmds(str);
984 			if (fusedcmd_ok)
985 				free(str);
986 			return (char **)NULL;
987 		}
988 
989 		register size_t j = 0;
990 		size_t str_len = strlen(str), len = 0, internal_ok = 0;
991 		char *buf = (char *)NULL;
992 
993 		/* Get each word (cmd) in STR */
994 		buf = (char *)xcalloc(str_len + 1, sizeof(char));
995 		for (j = 0; j < str_len; j++) {
996 			while (str[j] && str[j] != ' ' && str[j] != ';' && str[j] != '&') {
997 				buf[len++] = str[j++];
998 			}
999 
1000 			if (strcmp(buf, "&&") != 0) {
1001 				if (is_internal_c(buf)) {
1002 					internal_ok = 1;
1003 					break;
1004 				}
1005 			}
1006 
1007 			memset(buf, '\0', len);
1008 			len = 0;
1009 		}
1010 
1011 		free(buf);
1012 		buf = (char *)NULL;
1013 
1014 		if (internal_ok) {
1015 			exec_chained_cmds(str);
1016 			if (fusedcmd_ok)
1017 				free(str);
1018 			return (char **)NULL;
1019 		}
1020 	}
1021 
1022 	if (flags & IS_USRVAR_DEF || send_shell) {
1023 		/* Remove leading spaces, again */
1024 		char *p = str;
1025 		while (*p == ' ' || *p == '\t')
1026 			p++;
1027 
1028 		args_n = 0;
1029 
1030 		char **cmd = (char **)NULL;
1031 		cmd = (char **)xnmalloc(2, sizeof(char *));
1032 		cmd[0] = savestring(p, strlen(p));
1033 		cmd[1] = (char *)NULL;
1034 
1035 		p = (char *)NULL;
1036 
1037 		if (fusedcmd_ok)
1038 			free(str);
1039 
1040 		return cmd;
1041 		/* If ";cmd" or ":cmd" the whole input line will be send to
1042 		 * exec_cmd() and will be executed by the system shell via
1043 		 * execle(). Since we don't run split_str() here, dequoting
1044 		 * and deescaping is performed directly by the system shell */
1045 	}
1046 
1047 		/* ################################################
1048 		 * #     1) SPLIT INPUT STRING INTO SUBSTRINGS    #
1049 		 * ################################################ */
1050 
1051 	/* split_str() returns an array of strings without leading,
1052 	 * terminating and double spaces. */
1053 	char **substr = split_str(str);
1054 
1055 	/** ###################### */
1056 	if (fusedcmd_ok) /* Just in case split_fusedcmd returned NULL */
1057 		free(str);
1058 	/** ###################### */
1059 
1060 	/* NOTE: isspace() not only checks for space, but also for new line,
1061 	 * carriage return, vertical and horizontal TAB. Be careful when
1062 	 * replacing this function. */
1063 
1064 	if (!substr)
1065 		return (char **)NULL;
1066 
1067 	/* Handle background/foreground process */
1068 	bg_proc = 0;
1069 
1070 	if (*substr[args_n] == '&' && !*(substr[args_n] + 1)) {
1071 		bg_proc = 1;
1072 		free(substr[args_n]);
1073 		substr[args_n--] = (char *)NULL;
1074 	} else {
1075 		size_t len = strlen(substr[args_n]);
1076 		if (substr[args_n][len - 1] == '&' && !substr[args_n][len]) {
1077 			substr[args_n][len - 1] = '\0';
1078 			bg_proc = 1;
1079 		}
1080 	}
1081 
1082 					/* ######################
1083 					 * #     TRASH AS RM    #
1084 					 * ###################### */
1085 #ifndef _NO_TRASH
1086 	if (tr_as_rm && substr[0] && *substr[0] == 'r' && !substr[0][1]) {
1087 		substr[0] = (char *)xrealloc(substr[0], 3 * sizeof(char));
1088 		*substr[0] = 't';
1089 		substr[0][1] = 'r';
1090 		substr[0][2] = '\0';
1091 	}
1092 #endif
1093 				/* ##############################
1094 				 * #   2) BUILTIN EXPANSIONS    #
1095 				 * ##############################
1096 
1097 	 * Ranges, sel, ELN, pinned dirs, bookmarks, and internal variables.
1098 	 * These expansions are specific to CliFM. To be able to use them
1099 	 * even with external commands, they must be expanded here, before
1100 	 * sending the input string, in case the command is external, to
1101 	 * the system shell */
1102 
1103 	is_sel = 0, sel_is_last = 0;
1104 
1105 	size_t int_array_max = 10, ranges_ok = 0;
1106 	int *range_array = (int *)xnmalloc(int_array_max, sizeof(int));
1107 
1108 	for (i = 0; i <= args_n; i++) {
1109 		if (!substr[i])
1110 			continue;
1111 
1112 		register size_t j = 0;
1113 		/* Replace . and .. by absolute paths */
1114 		if (*substr[i] == '.' && (!substr[i][1] || (substr[i][1] == '.'
1115 		&& !substr[i][2]))) {
1116 			char *tmp = (char *)NULL;
1117 			tmp = realpath(substr[i], NULL);
1118 			substr[i] = (char *)xrealloc(substr[i], (strlen(tmp) + 1)
1119 											* sizeof(char));
1120 			strcpy(substr[i], tmp);
1121 			free(tmp);
1122 		}
1123 
1124 			/* ######################################
1125 			 * #     2.a) FASTBACK EXPANSION        #
1126 			 * ###################################### */
1127 
1128 		if (*substr[i] == '.' && substr[i][1] == '.' && substr[i][2] == '.') {
1129 			char *tmp = fastback(substr[i]);
1130 			if (tmp) {
1131 				substr[i] = (char *)xrealloc(substr[i], (strlen(tmp) + 1)
1132 														* sizeof(char));
1133 				strcpy(substr[i], tmp);
1134 				free(tmp);
1135 			}
1136 		}
1137 
1138 			/* ######################################
1139 			 * #     2.b) PINNED DIR EXPANSION      #
1140 			 * ###################################### */
1141 
1142 		if (*substr[i] == ',' && !substr[i][1] && pinned_dir) {
1143 			substr[i] = (char *)xrealloc(substr[i], (strlen(pinned_dir) + 1)
1144 													* sizeof(char));
1145 			strcpy(substr[i], pinned_dir);
1146 		}
1147 
1148 			/* ######################################
1149 			 * #      2.c) BOOKMARKS EXPANSION      #
1150 			 * ###################################### */
1151 
1152 		/* Expand bookmark names into paths */
1153 		if (expand_bookmarks) {
1154 			int bm_exp = 0;
1155 
1156 			for (j = 0; j < bm_n; j++) {
1157 				if (bookmarks[j].name && *substr[i] == *bookmarks[j].name
1158 				&& strcmp(substr[i], bookmarks[j].name) == 0) {
1159 
1160 					/* Do not expand bookmark names that conflicts
1161 					 * with a file name in CWD */
1162 					int conflict = 0, k = (int)files;
1163 					while (--k >= 0) {
1164 						if (*bookmarks[j].name == *file_info[k].name
1165 						&& strcmp(bookmarks[j].name, file_info[k].name) == 0) {
1166 							conflict = 1;
1167 							break;
1168 						}
1169 					}
1170 
1171 					if (!conflict && bookmarks[j].path) {
1172 						substr[i] = (char *)xrealloc(substr[i],
1173 						    (strlen(bookmarks[j].path) + 1) * sizeof(char));
1174 						strcpy(substr[i], bookmarks[j].path);
1175 
1176 						bm_exp = 1;
1177 
1178 						break;
1179 					}
1180 				}
1181 			}
1182 
1183 			/* Do not perform further checks on the expanded bookmark */
1184 			if (bm_exp)
1185 				continue;
1186 		}
1187 
1188 		/* ############################################# */
1189 
1190 		size_t substr_len = strlen(substr[i]);
1191 
1192 		/* Check for ranges */
1193 		for (j = 0; substr[i][j]; j++) {
1194 			/* If some alphabetic char, besides '-', is found in the
1195 			 * string, we have no range */
1196 			if (substr[i][j] != '-' && !_ISDIGIT(substr[i][j]))
1197 				break;
1198 
1199 			/* If a range is found, store its index */
1200 			if (j > 0 && j < substr_len && substr[i][j] == '-' &&
1201 			    _ISDIGIT(substr[i][j - 1]) && _ISDIGIT(substr[i][j + 1]))
1202 				if (ranges_ok < int_array_max)
1203 					range_array[ranges_ok++] = (int)i;
1204 		}
1205 
1206 		/* Expand 'sel' only as an argument, not as command */
1207 		if (i > 0 && *substr[i] == 's' && strcmp(substr[i], "sel") == 0)
1208 			is_sel = (short)i;
1209 	}
1210 
1211 			/* ####################################
1212 			 * #       2.d) RANGES EXPANSION      #
1213 			 * ####################################*/
1214 
1215 	/* Expand expressions like "1-3" to "1 2 3" if all the numbers in
1216 	  * the range correspond to an ELN */
1217 
1218 	if (ranges_ok) {
1219 		size_t old_ranges_n = 0;
1220 		register size_t r = 0;
1221 
1222 		for (r = 0; r < ranges_ok; r++) {
1223 			size_t ranges_n = 0;
1224 			int *ranges = expand_range(substr[range_array[r] +
1225 							  (int)old_ranges_n], 1);
1226 			if (ranges) {
1227 				register size_t j = 0;
1228 
1229 				for (ranges_n = 0; ranges[ranges_n]; ranges_n++);
1230 
1231 				char **ranges_cmd = (char **)NULL;
1232 				ranges_cmd = (char **)xcalloc(args_n + ranges_n + 2,
1233 				    sizeof(char *));
1234 
1235 				for (i = 0; i < (size_t)range_array[r] + old_ranges_n; i++)
1236 					ranges_cmd[j++] = savestring(substr[i], strlen(substr[i]));
1237 
1238 				for (i = 0; i < ranges_n; i++) {
1239 					ranges_cmd[j] = (char *)xcalloc((size_t)DIGINUM(ranges[i])
1240 													+ 1, sizeof(int));
1241 					sprintf(ranges_cmd[j++], "%d", ranges[i]);
1242 				}
1243 
1244 				for (i = (size_t)range_array[r] + old_ranges_n + 1;
1245 				     i <= args_n; i++) {
1246 					ranges_cmd[j++] = savestring(substr[i],
1247 					    strlen(substr[i]));
1248 				}
1249 
1250 				ranges_cmd[j] = NULL;
1251 				free(ranges);
1252 
1253 				for (i = 0; i <= args_n; i++)
1254 					free(substr[i]);
1255 
1256 				substr = (char **)xrealloc(substr, (args_n + ranges_n + 2)
1257 													* sizeof(char *));
1258 
1259 				for (i = 0; i < j; i++) {
1260 					substr[i] = savestring(ranges_cmd[i], strlen(ranges_cmd[i]));
1261 					free(ranges_cmd[i]);
1262 				}
1263 
1264 				free(ranges_cmd);
1265 				args_n = j - 1;
1266 			}
1267 
1268 			old_ranges_n += (ranges_n - 1);
1269 		}
1270 	}
1271 
1272 	free(range_array);
1273 
1274 				/* ##########################
1275 				 * #   2.e) SEL EXPANSION   #
1276 				 * ##########################*/
1277 
1278 	/*  if (is_sel && *substr[0] != '/') { */
1279 	if (is_sel) {
1280 		if ((size_t)is_sel == args_n)
1281 			sel_is_last = 1;
1282 
1283 		if (sel_n) {
1284 			register size_t j = 0;
1285 			char **sel_array = (char **)NULL;
1286 			sel_array = (char **)xnmalloc(args_n + sel_n + 2, sizeof(char *));
1287 
1288 			for (i = 0; i < (size_t)is_sel; i++) {
1289 				if (!substr[i])
1290 					continue;
1291 				sel_array[j++] = savestring(substr[i], strlen(substr[i]));
1292 			}
1293 
1294 			for (i = 0; i < sel_n; i++) {
1295 				/* Escape selected file names and copy them into tmp
1296 				 * array */
1297 				char *esc_str = escape_str(sel_elements[i]);
1298 				if (esc_str) {
1299 					sel_array[j++] = savestring(esc_str, strlen(esc_str));
1300 					free(esc_str);
1301 					esc_str = (char *)NULL;
1302 				} else {
1303 					fprintf(stderr, _("%s: %s: Error quoting file name\n"),
1304 					    PROGRAM_NAME, sel_elements[j]);
1305 					/* Free elements selected thus far and and all the
1306 					 * input substrings */
1307 					register size_t k = 0;
1308 					for (k = 0; k < j; k++)
1309 						free(sel_array[k]);
1310 					free(sel_array);
1311 
1312 					for (k = 0; k <= args_n; k++)
1313 						free(substr[k]);
1314 					free(substr);
1315 
1316 					return (char **)NULL;
1317 				}
1318 			}
1319 
1320 			for (i = (size_t)is_sel + 1; i <= args_n; i++)
1321 				sel_array[j++] = savestring(substr[i], strlen(substr[i]));
1322 
1323 			for (i = 0; i <= args_n; i++)
1324 				free(substr[i]);
1325 
1326 			substr = (char **)xrealloc(substr, (args_n + sel_n + 2)
1327 										* sizeof(char *));
1328 
1329 			for (i = 0; i < j; i++) {
1330 				substr[i] = savestring(sel_array[i], strlen(sel_array[i]));
1331 				free(sel_array[i]);
1332 			}
1333 
1334 			free(sel_array);
1335 			substr[i] = (char *)NULL;
1336 			args_n = j - 1;
1337 		}
1338 
1339 		else {
1340 			/* 'sel' is an argument, but there are no selected files. */
1341 			fprintf(stderr, _("%c%s: There are no selected files%c"),
1342 			    kb_shortcut ? '\n' : '\0', PROGRAM_NAME,
1343 			    kb_shortcut ? '\0' : '\n');
1344 
1345 			register size_t j = 0;
1346 			for (j = 0; j <= args_n; j++)
1347 				free(substr[j]);
1348 			free(substr);
1349 
1350 			return (char **)NULL;
1351 		}
1352 	}
1353 
1354 	int stdin_dir_ok = 0;
1355 	if (stdin_tmp_dir && strcmp(ws[cur_ws].path, stdin_tmp_dir) == 0)
1356 		stdin_dir_ok = 1;
1357 
1358 	for (i = 0; i <= args_n; i++) {
1359 		if (!substr[i])
1360 			continue;
1361 
1362 				/* ##########################
1363 				 * #   2.f) ELN EXPANSION   #
1364 				 * ##########################*/
1365 
1366 		/* If autocd is set to false, i must be bigger than zero because
1367 		 * the first string in comm_array, the command name, should NOT
1368 		 * be expanded, but only arguments. Otherwise, if the expanded
1369 		 * ELN happens to be a program name as well, this program will
1370 		 * be executed, and this, for sure, is to be avoided */
1371 
1372 		/* The 'sort', 'mf', 'ws', and 'jo' commands take digits as
1373 		 * arguments. So, do not expand ELN's in these cases */
1374 		if (substr[0] && strcmp(substr[0], "mf") != 0
1375 		&& strcmp(substr[0], "st") != 0 && strcmp(substr[0], "ws") != 0
1376 		&& strcmp(substr[0], "sort") != 0 && strcmp(substr[0], "jo") != 0) {
1377 
1378 			if (is_number(substr[i])) {
1379 				/* Expand first word only if autocd is set to true */
1380 				if ((i == 0 && !autocd && !auto_open) || !substr[i])
1381 					continue;
1382 
1383 				int num = atoi(substr[i]);
1384 				/* Expand numbers only if there is a corresponding ELN */
1385 
1386 				/* Do not expand ELN if there is a file named as the
1387 				 * ELN */
1388 				if (eln_as_file_n) {
1389 					int conflict = 0;
1390 					if (eln_as_file_n > 1) {
1391 						size_t j;
1392 
1393 						for (j = 0; j < eln_as_file_n; j++) {
1394 							if (atoi(file_info[eln_as_file[j]].name) == num) {
1395 								conflict = num;
1396 								/* One conflicting file name is enough */
1397 								break;
1398 							}
1399 						}
1400 					} else {
1401 						if (atoi(file_info[eln_as_file[0]].name) == num)
1402 							conflict = num;
1403 					}
1404 
1405 					if (conflict) {
1406 						size_t j;
1407 
1408 						for (j = 0; j <= args_n; j++)
1409 							free(substr[j]);
1410 						free(substr);
1411 
1412 						fprintf(stderr, _("%s: %d: ELN-filename "
1413 							"conflict. Bypass internal expansions "
1414 							"to fix this issue: ';CMD "
1415 							"FILENAME'\n"), PROGRAM_NAME, conflict);
1416 						return (char **)NULL;
1417 					}
1418 				}
1419 
1420 				if (num > 0 && num <= (int)files) {
1421 					/* Replace the ELN by the corresponding escaped
1422 					 * file name */
1423 					int j = num - 1;
1424 					char *esc_str = escape_str(file_info[j].name);
1425 
1426 					if (esc_str) {
1427 						if (file_info[j].dir &&
1428 						    file_info[j].name[file_info[j].len - 1] != '/') {
1429 							substr[i] = (char *)xrealloc(substr[i],
1430 							    (strlen(esc_str) + 2) * sizeof(char));
1431 							sprintf(substr[i], "%s/", esc_str);
1432 						} else {
1433 							substr[i] = (char *)xrealloc(substr[i],
1434 							    (strlen(esc_str) + 1) * sizeof(char));
1435 							strcpy(substr[i], esc_str);
1436 						}
1437 						free(esc_str);
1438 						esc_str = (char *)NULL;
1439 					} else {
1440 						fprintf(stderr, _("%s: %s: Error quoting "
1441 								"file name\n"),
1442 								PROGRAM_NAME, file_info[num - 1].name);
1443 						/* Free whatever was allocated thus far */
1444 
1445 						for (j = 0; j <= (int)args_n; j++)
1446 							free(substr[j]);
1447 						free(substr);
1448 						return (char **)NULL;
1449 					}
1450 				}
1451 			}
1452 		}
1453 
1454 		/* #############################################
1455 		 * #   2.g) USER DEFINED VARIABLES EXPANSION   #
1456 		 * #############################################*/
1457 
1458 		if (int_vars) {
1459 			if (substr[i][0] == '$' && substr[i][1] != '(' && substr[i][1] != '{') {
1460 				char *var_name = strchr(substr[i], '$');
1461 				if (var_name && *(++var_name)) {
1462 					int j = (int)usrvar_n;
1463 					while (--j >= 0) {
1464 						if (*var_name == *usr_var[j].name
1465 						&& strcmp(var_name, usr_var[j].name) == 0) {
1466 							substr[i] = (char *)xrealloc(substr[i],
1467 								(strlen(usr_var[j].value) + 1) * sizeof(char));
1468 							strcpy(substr[i], usr_var[j].value);
1469 							break;
1470 						}
1471 					}
1472 				} else {
1473 					fprintf(stderr, _("%s: %s: Error getting variable name\n"),
1474 							PROGRAM_NAME, substr[i]);
1475 					size_t j;
1476 					for (j = 0; j <= args_n; j++)
1477 						free(substr[j]);
1478 					free(substr);
1479 					return (char **)NULL;
1480 				}
1481 			}
1482 		}
1483 
1484 				/* ###############################
1485 				 * #    ENVIRONEMNT VARIABLES    #
1486 				 * ###############################*/
1487 
1488 		if (*substr[i] == '$') {
1489 			char *p = getenv(substr[i] + 1);
1490 			if (p) {
1491 				substr[i] = (char *)xrealloc(substr[i], (strlen(p) + 1) * sizeof(char));
1492 				strcpy(substr[i], p);
1493 			}
1494 		}
1495 
1496 		/* We are in STDIN_TMP_DIR: Expand symlinks to target */
1497 		if (stdin_dir_ok) {
1498 			char *real_path = realpath(substr[i], NULL);
1499 			if (real_path) {
1500 				substr[i] = (char *)xrealloc(substr[i],
1501 				    (strlen(real_path) + 1) * sizeof(char));
1502 				strcpy(substr[i], real_path);
1503 				free(real_path);
1504 			}
1505 		}
1506 	}
1507 
1508 	/* #### 3) NULL TERMINATE THE INPUT STRING ARRAY #### */
1509 	substr = (char **)xrealloc(substr, sizeof(char *) * (args_n + 2));
1510 	substr[args_n + 1] = (char *)NULL;
1511 
1512 	if (!is_internal(substr[0]))
1513 		return substr;
1514 
1515 	/* #############################################################
1516 	 * #               ONLY FOR INTERNAL COMMANDS                  #
1517 	 * #############################################################*/
1518 
1519 	/* Some functions of CliFM are purely internal, that is, they are not
1520 	 * wrappers of a shell command and do not call the system shell at all.
1521 	 * For this reason, some expansions normally made by the system shell
1522 	 * must be made here (in the lobby [got it?]) in order to be able to
1523 	 * understand these expansions at all. */
1524 
1525 		/* ###############################################
1526 		 * #   3) WILDCARD, BRACE, AND TILDE EXPANSION   #
1527 		 * ############################################### */
1528 
1529 	int *glob_array = (int *)xnmalloc(int_array_max, sizeof(int));
1530 	size_t glob_n = 0;
1531 #if !defined(__HAIKU__) && !defined(__OpenBSD__)
1532 	int *word_array = (int *)xnmalloc(int_array_max, sizeof(int));
1533 	size_t word_n = 0;
1534 #endif
1535 
1536 	for (i = 0; substr[i]; i++) {
1537 		/* Do not perform any of the expansions below for selected
1538 		 * elements: they are full path file names that, as such, do not
1539 		 * need any expansion */
1540 		if (is_sel) { /* is_sel is true only for the current input and if
1541 			there was some "sel" keyword in it */
1542 			/* Strings between is_sel and sel_n are selected file names */
1543 			if (i >= (size_t)is_sel && i <= sel_n)
1544 				continue;
1545 		}
1546 
1547 		/* Ignore the first string of the search function: it will be
1548 		 * expanded by the search function itself */
1549 		if (substr[0][0] == '/' && i == 0)
1550 			continue;
1551 
1552 		/* Tilde expansion is made by glob() */
1553 		if (*substr[i] == '~') {
1554 			if (glob_n < int_array_max)
1555 				glob_array[glob_n++] = (int)i;
1556 		}
1557 
1558 		register size_t j = 0;
1559 		for (j = 0; substr[i][j]; j++) {
1560 			/* Brace and wildcard expansion is made by glob()
1561 			 * as well */
1562 			if ((substr[i][j] == '*' || substr[i][j] == '?'
1563 			|| substr[i][j] == '[' || substr[i][j] == '{')
1564 			&& substr[i][j + 1] != ' ') {
1565 				/* Strings containing these characters are taken as
1566 			 * wildacard patterns and are expanded by the glob
1567 			 * function. See man (7) glob */
1568 				if (glob_n < int_array_max)
1569 					glob_array[glob_n++] = (int)i;
1570 			}
1571 
1572 #if !defined(__HAIKU__) && !defined(__OpenBSD__)
1573 			/* Command substitution is made by wordexp() */
1574 			if (substr[i][j] == '$' && (substr[i][j + 1] == '('
1575 			|| substr[i][j + 1] == '{')) {
1576 				if (word_n < int_array_max)
1577 					word_array[word_n++] = (int)i;
1578 			}
1579 
1580 			if (substr[i][j] == '`' && substr[i][j + 1] != ' ') {
1581 				if (word_n < int_array_max)
1582 					word_array[word_n++] = (int)i;
1583 			}
1584 #endif /* __HAIKU__ */
1585 		}
1586 	}
1587 
1588 	/* Do not expand if command is deselect, sel or untrash, just to
1589 	 * allow the use of "*" for desel and untrash ("ds *" and "u *")
1590 	 * and to let the sel function handle patterns itself */
1591 	if (glob_n && strcmp(substr[0], "s") != 0 && strcmp(substr[0], "sel") != 0
1592 	&& strcmp(substr[0], "ds") != 0 && strcmp(substr[0], "desel") != 0
1593 	&& strcmp(substr[0], "u") != 0 && strcmp(substr[0], "undel") != 0
1594 	&& strcmp(substr[0], "untrash") != 0) {
1595 		/* 1) Expand glob
1596 		2) Create a new array, say comm_array_glob, large enough to store
1597 		   the expanded glob and the remaining (non-glob) arguments
1598 		   (args_n+gl_pathc)
1599 		3) Copy into this array everything before the glob
1600 		   (i=0;i<glob_char;i++)
1601 		4) Copy the expanded elements (if none, copy the original element,
1602 		   comm_array[glob_char])
1603 		5) Copy the remaining elements (i=glob_char+1;i<=args_n;i++)
1604 		6) Free the old comm_array and fill it with comm_array_glob
1605 	  */
1606 		size_t old_pathc = 0;
1607 		/* glob_array stores the index of the globbed strings. However,
1608 		 * once the first expansion is done, the index of the next globbed
1609 		 * string has changed. To recover the next globbed string, and
1610 		 * more precisely, its index, we only need to add the amount of
1611 		 * files matched by the previous instances of glob(). Example:
1612 		 * if original indexes were 2 and 4, once 2 is expanded 4 stores
1613 		 * now some of the files expanded in 2. But if we add to 4 the
1614 		 * amount of files expanded in 2 (gl_pathc), we get now the
1615 		 * original globbed string pointed by 4.
1616 		*/
1617 		register size_t g = 0;
1618 		for (g = 0; g < (size_t)glob_n; g++) {
1619 			glob_t globbuf;
1620 
1621 			if (glob(substr[glob_array[g] + (int)old_pathc],
1622 				GLOB_BRACE | GLOB_TILDE, NULL, &globbuf) != EXIT_SUCCESS) {
1623 				globfree(&globbuf);
1624 				continue;
1625 			}
1626 
1627 			if (globbuf.gl_pathc) {
1628 				register size_t j = 0;
1629 				char **glob_cmd = (char **)NULL;
1630 				glob_cmd = (char **)xcalloc(args_n + globbuf.gl_pathc + 1,
1631 											sizeof(char *));
1632 
1633 				for (i = 0; i < ((size_t)glob_array[g] + old_pathc); i++)
1634 					glob_cmd[j++] = savestring(substr[i], strlen(substr[i]));
1635 
1636 				for (i = 0; i < globbuf.gl_pathc; i++) {
1637 					/* Do not match "." or ".." */
1638 					if (strcmp(globbuf.gl_pathv[i], ".") == 0
1639 					|| strcmp(globbuf.gl_pathv[i], "..") == 0)
1640 						continue;
1641 
1642 					/* Escape the globbed file name and copy it */
1643 					char *esc_str = escape_str(globbuf.gl_pathv[i]);
1644 					if (esc_str) {
1645 						glob_cmd[j++] = savestring(esc_str, strlen(esc_str));
1646 						free(esc_str);
1647 					} else {
1648 						fprintf(stderr, _("%s: %s: Error quoting "
1649 							"file name\n"), PROGRAM_NAME, globbuf.gl_pathv[i]);
1650 						register size_t k = 0;
1651 						for (k = 0; k < j; k++)
1652 							free(glob_cmd[k]);
1653 						free(glob_cmd);
1654 						glob_cmd = (char **)NULL;
1655 
1656 						for (k = 0; k <= args_n; k++)
1657 							free(substr[k]);
1658 						free(substr);
1659 						globfree(&globbuf);
1660 						return (char **)NULL;
1661 					}
1662 				}
1663 
1664 				for (i = (size_t)glob_array[g] + old_pathc + 1;
1665 				i <= args_n; i++)
1666 					glob_cmd[j++] = savestring(substr[i], strlen(substr[i]));
1667 
1668 				glob_cmd[j] = (char *)NULL;
1669 
1670 				for (i = 0; i <= args_n; i++)
1671 					free(substr[i]);
1672 				free(substr);
1673 
1674 				substr = glob_cmd;
1675 				glob_cmd = (char **)NULL;
1676 				args_n = j - 1;
1677 			}
1678 
1679 			old_pathc += (globbuf.gl_pathc - 1);
1680 			globfree(&globbuf);
1681 		}
1682 	}
1683 
1684 	free(glob_array);
1685 
1686 		/* #############################################
1687 		 * #    4) COMMAND & PARAMETER SUBSTITUTION    #
1688 		 * ############################################# */
1689 #if !defined(__HAIKU__) && !defined(__OpenBSD__)
1690 	if (word_n) {
1691 		size_t old_pathc = 0;
1692 		register size_t w = 0;
1693 		for (w = 0; w < (size_t)word_n; w++) {
1694 			wordexp_t wordbuf;
1695 			if (wordexp(substr[word_array[w] + (int)old_pathc],
1696 				&wordbuf, 0) != EXIT_SUCCESS) {
1697 				wordfree(&wordbuf);
1698 				continue;
1699 			}
1700 
1701 			if (wordbuf.we_wordc) {
1702 				register size_t j = 0;
1703 				char **word_cmd = (char **)NULL;
1704 
1705 				word_cmd = (char **)xcalloc(args_n + wordbuf.we_wordc + 1,
1706 											sizeof(char *));
1707 
1708 				for (i = 0; i < ((size_t)word_array[w] + old_pathc); i++)
1709 					word_cmd[j++] = savestring(substr[i], strlen(substr[i]));
1710 
1711 				for (i = 0; i < wordbuf.we_wordc; i++) {
1712 					/* Escape the globbed file name and copy it*/
1713 					char *esc_str = escape_str(wordbuf.we_wordv[i]);
1714 					if (esc_str) {
1715 						word_cmd[j++] = savestring(esc_str, strlen(esc_str));
1716 						free(esc_str);
1717 					} else {
1718 						fprintf(stderr, _("%s: %s: Error quoting "
1719 							"file name\n"), PROGRAM_NAME, wordbuf.we_wordv[i]);
1720 
1721 						register size_t k = 0;
1722 						for (k = 0; k < j; k++)
1723 							free(word_cmd[k]);
1724 						free(word_cmd);
1725 
1726 						word_cmd = (char **)NULL;
1727 
1728 						for (k = 0; k <= args_n; k++)
1729 							free(substr[k]);
1730 						free(substr);
1731 						return (char **)NULL;
1732 					}
1733 				}
1734 
1735 				for (i = (size_t)word_array[w] + old_pathc + 1;
1736 				i <= args_n; i++)
1737 					word_cmd[j++] = savestring(substr[i], strlen(substr[i]));
1738 
1739 				word_cmd[j] = (char *)NULL;
1740 
1741 				for (i = 0; i <= args_n; i++)
1742 					free(substr[i]);
1743 				free(substr);
1744 				substr = word_cmd;
1745 				word_cmd = (char **)NULL;
1746 				args_n = j - 1;
1747 			}
1748 
1749 			old_pathc += (wordbuf.we_wordc - 1);
1750 			wordfree(&wordbuf);
1751 		}
1752 	}
1753 
1754 	free(word_array);
1755 #endif /* __HAIKU__ */
1756 
1757 	if (substr[0] && (*substr[0] == 'd' || *substr[0] == 'u')
1758 	&& (strcmp(substr[0], "desel") == 0 || strcmp(substr[0], "undel") == 0
1759 	|| strcmp(substr[0], "untrash") == 0)) {
1760 		/* Null terminate the input string array (again) */
1761 		substr = (char **)xrealloc(substr, (args_n + 2) * sizeof(char *));
1762 		substr[args_n + 1] = (char *)NULL;
1763 		return substr;
1764 	}
1765 
1766 		/* #############################################
1767 		 * #             5) REGEX EXPANSION            #
1768 		 * ############################################# */
1769 
1770 	if ((*substr[0] == 's' && (!substr[0][1] || strcmp(substr[0], "sel") == 0))
1771 	|| (*substr[0] == 'n' && (!substr[0][1] || strcmp(substr[0], "new") == 0)))
1772 		return substr;
1773 
1774 	char **regex_files = (char **)xnmalloc(files + args_n + 2, sizeof(char *));
1775 	size_t j, r_files = 0;
1776 
1777 	for (i = 0; substr[i]; i++) {
1778 		if (r_files > (files + args_n))
1779 			break;
1780 
1781 		/* Ignore the first string of the search function: it will be
1782 		 * expanded by the search function itself */
1783 		if (*substr[0] == '/') {
1784 			regex_files[r_files++] = substr[i];
1785 			continue;
1786 		}
1787 
1788 		/* At this point, all file names are escaped. But check_regex()
1789 		 * needs unescaped file names. So, let's deescape it */
1790 		char *p = strchr(substr[i], '\\');
1791 		char *dstr = (char *)NULL;
1792 		if (p)
1793 			dstr = dequote_str(substr[i], 0);
1794 		int ret = check_regex(dstr ? dstr : substr[i]);
1795 		free(dstr);
1796 		if (ret != EXIT_SUCCESS) {
1797 			regex_files[r_files++] = substr[i];
1798 			continue;
1799 		}
1800 
1801 		regex_t regex;
1802 		if (regcomp(&regex, substr[i], REG_NOSUB | REG_EXTENDED) != EXIT_SUCCESS) {
1803 			/*          fprintf(stderr, "%s: %s: Invalid regular expression",
1804 					PROGRAM_NAME, substr[i]); */
1805 			regfree(&regex);
1806 			regex_files[r_files++] = substr[i];
1807 			continue;
1808 		}
1809 
1810 		int reg_found = 0;
1811 
1812 		for (j = 0; j < files; j++) {
1813 			if (regexec(&regex, file_info[j].name, 0, NULL, 0) == EXIT_SUCCESS) {
1814 				regex_files[r_files++] = file_info[j].name;
1815 				reg_found = 1;
1816 			}
1817 		}
1818 
1819 		if (!reg_found)
1820 			regex_files[r_files++] = substr[i];
1821 
1822 		regfree(&regex);
1823 	}
1824 
1825 	if (r_files) {
1826 		regex_files[r_files] = (char *)NULL;
1827 		char **tmp_files = (char **)xnmalloc(r_files + 2, sizeof(char *));
1828 		size_t k = 0;
1829 		for (j = 0; regex_files[j]; j++)
1830 			tmp_files[k++] = savestring(regex_files[j], strlen(regex_files[j]));
1831 		tmp_files[k] = (char *)NULL;
1832 
1833 		for (j = 0; j <= args_n; j++)
1834 			free(substr[j]);
1835 		free(substr);
1836 
1837 		substr = tmp_files;
1838 		tmp_files = (char **)NULL;
1839 		args_n = k - 1;
1840 		free(tmp_files);
1841 	}
1842 
1843 	free(regex_files);
1844 	substr = (char **)xrealloc(substr, (args_n + 2) * sizeof(char *));
1845 	substr[args_n + 1] = (char *)NULL;
1846 
1847 	return substr;
1848 }
1849 
1850 /* Reduce "$HOME" to tilde ("~"). The new_path variable is always either
1851  * "$HOME" or "$HOME/file", that's why there's no need to check for
1852  * "/file" */
1853 char *
home_tilde(const char * new_path)1854 home_tilde(const char *new_path)
1855 {
1856 	if (!home_ok || !new_path || !*new_path || !user.home)
1857 		return (char *)NULL;
1858 
1859 	char *path_tilde = (char *)NULL;
1860 
1861 	/* If path == HOME */
1862 	if (new_path[1] == user.home[1] && strcmp(new_path, user.home) == 0) {
1863 		path_tilde = (char *)xnmalloc(2, sizeof(char));
1864 		path_tilde[0] = '~';
1865 		path_tilde[1] = '\0';
1866 	} else if (new_path[1] == user.home[1]
1867 	&& strncmp(new_path, user.home, user.home_len) == 0) {
1868 		/* If path == HOME/file */
1869 		path_tilde = (char *)xnmalloc(strlen(new_path + user.home_len + 1) + 3,
1870 										sizeof(char));
1871 		sprintf(path_tilde, "~/%s", new_path + user.home_len + 1);
1872 	} else {
1873 		path_tilde = (char *)xnmalloc(strlen(new_path) + 1, sizeof(char));
1874 		strcpy(path_tilde, new_path);
1875 	}
1876 
1877 	return path_tilde;
1878 }
1879 
1880 /* Expand a range of numbers given by str. It will expand the range
1881  * provided that both extremes are numbers, bigger than zero, equal or
1882  * smaller than the amount of files currently listed on the screen, and
1883  * the second (right) extreme is bigger than the first (left). Returns
1884  * an array of int's with the expanded range or NULL if one of the
1885  * above conditions is not met */
1886 int *
expand_range(char * str,int listdir)1887 expand_range(char *str, int listdir)
1888 {
1889 	if (!str || !*str)
1890 		return (int *)NULL;
1891 
1892 	char *p = strchr(str, '-');
1893 	if (!p || p == str || *(p - 1) < '0' || *(p - 1) > '9'
1894 	|| !*(p + 1) || *(p + 1) < '0' || *(p + 1) > '9')
1895 		return (int *)NULL;
1896 
1897 	*p = '\0';
1898 	int ret = is_number(str);
1899 	*p = '-';
1900 	if (!ret)
1901 		return (int *)NULL;
1902 
1903 	int afirst = atoi(str);
1904 
1905 	if (!is_number(++p))
1906 		return (int *)NULL;
1907 
1908 	int asecond = atoi(p);
1909 
1910 	if (listdir) {
1911 		if (afirst <= 0 || afirst > (int)files || asecond <= 0
1912 		|| asecond > (int)files || afirst >= asecond)
1913 			return (int *)NULL;
1914 	} else if (afirst >= asecond) {
1915 		return (int *)NULL;
1916 	}
1917 
1918 	int *buf = (int *)NULL;
1919 	buf = (int *)xcalloc((size_t)(asecond - afirst) + 2, sizeof(int));
1920 
1921 	size_t i, j = 0;
1922 	for (i = (size_t)afirst; i <= (size_t)asecond; i++)
1923 		buf[j++] = (int)i;
1924 
1925 	return buf;
1926 }
1927 
1928 /* used a lot.
1929  * creates a copy of a string */
1930 char *
savestring(const char * restrict str,size_t size)1931 savestring(const char *restrict str, size_t size)
1932 {
1933 	if (!str)
1934 		return (char *)NULL;
1935 
1936 	char *ptr = (char *)NULL;
1937 	ptr = (char *)malloc((size + 1) * sizeof(char));
1938 
1939 	if (!ptr)
1940 		return (char *)NULL;
1941 	strcpy(ptr, str);
1942 
1943 	return ptr;
1944 }
1945 
1946 /* Take a string and returns the same string escaped. If nothing to be
1947  * escaped, the original string is returned */
1948 char *
escape_str(const char * str)1949 escape_str(const char *str)
1950 {
1951 	if (!str)
1952 		return (char *)NULL;
1953 
1954 	size_t len = 0;
1955 	char *buf = (char *)NULL;
1956 
1957 	buf = (char *)xnmalloc(strlen(str) * 2 + 1, sizeof(char));
1958 
1959 	while (*str) {
1960 		if (is_quote_char(*str))
1961 			buf[len++] = '\\';
1962 		buf[len++] = *(str++);
1963 	}
1964 
1965 	buf[len] = '\0';
1966 	return buf;
1967 }
1968 
1969 /* Get all substrings from STR using IFS as substring separator, and,
1970  * if there is a range, expand it. Returns an array containing all
1971  * substrings in STR plus expandes ranges, or NULL if: STR is NULL or
1972  * empty, STR contains only IFS(s), or in case of memory allocation
1973  * error */
1974 char **
get_substr(char * str,const char ifs)1975 get_substr(char *str, const char ifs)
1976 {
1977 	if (!str || *str == '\0')
1978 		return (char **)NULL;
1979 
1980 	/* ############## SPLIT THE STRING #######################*/
1981 
1982 	char **substr = (char **)NULL;
1983 	void *p = (char *)NULL;
1984 	size_t str_len = strlen(str);
1985 	size_t length = 0, substr_n = 0;
1986 	char *buf = (char *)xnmalloc(str_len + 1, sizeof(char));
1987 
1988 	while (*str) {
1989 		while (*str != ifs && *str != '\0' && length < (str_len + 1))
1990 			buf[length++] = *(str++);
1991 		if (length) {
1992 			buf[length] = '\0';
1993 			p = (char *)realloc(substr, (substr_n + 1) * sizeof(char *));
1994 			if (!p) {
1995 				/* Free whatever was allocated so far */
1996 				size_t i;
1997 				for (i = 0; i < substr_n; i++)
1998 					free(substr[i]);
1999 				free(substr);
2000 				return (char **)NULL;
2001 			}
2002 			substr = (char **)p;
2003 			p = (char *)malloc(length + 1);
2004 
2005 			if (!p) {
2006 				size_t i;
2007 				for (i = 0; i < substr_n; i++)
2008 					free(substr[i]);
2009 				free(substr);
2010 				return (char **)NULL;
2011 			}
2012 
2013 			substr[substr_n] = p;
2014 			p = (char *)NULL;
2015 			xstrsncpy(substr[substr_n++], buf, length);
2016 			length = 0;
2017 		} else {
2018 			str++;
2019 		}
2020 	}
2021 
2022 	free(buf);
2023 
2024 	if (!substr_n)
2025 		return (char **)NULL;
2026 
2027 	size_t i = 0, j = 0;
2028 	p = (char *)realloc(substr, (substr_n + 1) * sizeof(char *));
2029 	if (!p) {
2030 		for (i = 0; i < substr_n; i++)
2031 			free(substr[i]);
2032 		free(substr);
2033 		substr = (char **)NULL;
2034 		return (char **)NULL;
2035 	}
2036 
2037 	substr = (char **)p;
2038 	p = (char *)NULL;
2039 	substr[substr_n] = (char *)NULL;
2040 
2041 	/* ################### EXPAND RANGES ######################*/
2042 
2043 	int afirst = 0, asecond = 0;
2044 
2045 	for (i = 0; substr[i]; i++) {
2046 		/* Check if substr is a valid range */
2047 		int ranges_ok = 0;
2048 		/* If range, get both extremes of it */
2049 		for (j = 1; substr[i][j]; j++) {
2050 			if (substr[i][j] == '-') {
2051 				/* Get strings before and after the dash */
2052 				char *q = strchr(substr[i], '-');
2053 				if (!q || !*q || q == substr[i] || *(q - 1) < '1'
2054 				|| *(q - 1) > '9' || !*(q + 1) || *(q + 1) < '1'
2055 				|| *(q + 1) > '9')
2056 					break;
2057 
2058 				*q = '\0';
2059 				char *first = savestring(substr[i], strlen(substr[i]));
2060 				*(q++) = '-';
2061 
2062 				if (!first)
2063 					break;
2064 
2065 				char *second = savestring(q, strlen(q));
2066 				if (!second) {
2067 					free(first);
2068 					break;
2069 				}
2070 
2071 				/* Make sure we have a valid range */
2072 				if (is_number(first) && is_number(second)) {
2073 					afirst = atoi(first), asecond = atoi(second);
2074 					if (asecond <= afirst) {
2075 						free(first);
2076 						free(second);
2077 						break;
2078 					}
2079 
2080 					ranges_ok = 1;
2081 					free(first);
2082 					free(second);
2083 				} else {
2084 					free(first);
2085 					free(second);
2086 					break;
2087 				}
2088 			}
2089 		}
2090 
2091 		if (!ranges_ok)
2092 			continue;
2093 
2094 		/* If a valid range */
2095 		size_t k = 0, next = 0;
2096 		char **rbuf = (char **)NULL;
2097 		rbuf = (char **)xnmalloc((substr_n + (size_t)(asecond - afirst) + 1),
2098 								sizeof(char *));
2099 		/* Copy everything before the range expression
2100 		 * into the buffer */
2101 		for (j = 0; j < i; j++)
2102 			rbuf[k++] = savestring(substr[j], strlen(substr[j]));
2103 
2104 		/* Copy the expanded range into the buffer */
2105 		for (j = (size_t)afirst; j <= (size_t)asecond; j++) {
2106 			rbuf[k] = (char *)xnmalloc((size_t)DIGINUM((int)j) + 1, sizeof(char));
2107 			sprintf(rbuf[k++], "%zu", j);
2108 		}
2109 
2110 		/* Copy everything after the range expression into
2111 		 * the buffer, if anything */
2112 		if (substr[i + 1]) {
2113 			next = k;
2114 			for (j = (i + 1); substr[j]; j++) {
2115 				rbuf[k++] = savestring(substr[j], strlen(substr[j]));
2116 			}
2117 		} else { /* If there's nothing after last range, there's no next
2118 		either */
2119 			next = 0;
2120 		}
2121 
2122 		/* Repopulate the original array with the expanded range and
2123 		 * remaining strings */
2124 		substr_n = k;
2125 		for (j = 0; substr[j]; j++)
2126 			free(substr[j]);
2127 
2128 		substr = (char **)xrealloc(substr, (substr_n + 1) * sizeof(char *));
2129 
2130 		for (j = 0; j < substr_n; j++) {
2131 			substr[j] = savestring(rbuf[j], strlen(rbuf[j]));
2132 			free(rbuf[j]);
2133 		}
2134 		free(rbuf);
2135 
2136 		substr[j] = (char *)NULL;
2137 
2138 		/* Proceede only if there's something after the last range */
2139 		if (next)
2140 			i = next;
2141 		else
2142 			break;
2143 	}
2144 
2145 	/* ############## REMOVE DUPLICATES ###############*/
2146 
2147 	char **dstr = (char **)NULL;
2148 	size_t len = 0, d;
2149 
2150 	for (i = 0; i < substr_n; i++) {
2151 		int duplicate = 0;
2152 		for (d = (i + 1); d < substr_n; d++) {
2153 			if (*substr[i] == *substr[d] && strcmp(substr[i], substr[d]) == 0) {
2154 				duplicate = 1;
2155 				break;
2156 			}
2157 		}
2158 
2159 		if (duplicate) {
2160 			free(substr[i]);
2161 			continue;
2162 		}
2163 
2164 		dstr = (char **)xrealloc(dstr, (len + 1) * sizeof(char *));
2165 		dstr[len++] = savestring(substr[i], strlen(substr[i]));
2166 		free(substr[i]);
2167 	}
2168 
2169 	free(substr);
2170 	dstr = (char **)xrealloc(dstr, (len + 1) * sizeof(char *));
2171 	dstr[len] = (char *)NULL;
2172 	return dstr;
2173 }
2174 
2175 /* This function simply deescapes whatever escaped chars it founds in
2176  * TEXT, so that readline can compare it to system file names when
2177  * completing paths. Returns a string containing text without escape
2178  * sequences */
2179 char *
dequote_str(char * text,int mt)2180 dequote_str(char *text, int mt)
2181 {
2182 	UNUSED(mt);
2183 	if (!text || !*text)
2184 		return (char *)NULL;
2185 
2186 	/* At most, we need as many bytes as text (in case no escape sequence
2187 	 * is found)*/
2188 	char *buf = (char *)NULL;
2189 	buf = (char *)xnmalloc(strlen(text) + 1, sizeof(char));
2190 	size_t len = 0;
2191 
2192 	while (*text) {
2193 		switch (*text) {
2194 		case '\\':
2195 			buf[len++] = *(++text);
2196 			break;
2197 		default:
2198 			buf[len++] = *text;
2199 			break;
2200 		}
2201 		if (!*text)
2202 			break;
2203 		text++;
2204 	}
2205 
2206 	buf[len] = '\0';
2207 	return buf;
2208 }
2209