xref: /linux/tools/perf/util/string.c (revision a067558e2fa72445e8f6e6b2dd372a82afae6e49)
1*a067558eSArnaldo Carvalho de Melo #include "string2.h"
2*a067558eSArnaldo Carvalho de Melo #include <linux/kernel.h>
3*a067558eSArnaldo Carvalho de Melo #include <linux/string.h>
4*a067558eSArnaldo Carvalho de Melo #include <stdlib.h>
586470930SIngo Molnar 
63d689ed6SArnaldo Carvalho de Melo #include "sane_ctype.h"
73d689ed6SArnaldo Carvalho de Melo 
8d2fb8b41SHitoshi Mitake #define K 1024LL
9d2fb8b41SHitoshi Mitake /*
10d2fb8b41SHitoshi Mitake  * perf_atoll()
11d2fb8b41SHitoshi Mitake  * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
12d2fb8b41SHitoshi Mitake  * and return its numeric value
13d2fb8b41SHitoshi Mitake  */
14d2fb8b41SHitoshi Mitake s64 perf_atoll(const char *str)
15d2fb8b41SHitoshi Mitake {
168ba7f6c2SAl Viro 	s64 length;
178ba7f6c2SAl Viro 	char *p;
188ba7f6c2SAl Viro 	char c;
19d2fb8b41SHitoshi Mitake 
20d2fb8b41SHitoshi Mitake 	if (!isdigit(str[0]))
21d2fb8b41SHitoshi Mitake 		goto out_err;
22d2fb8b41SHitoshi Mitake 
238ba7f6c2SAl Viro 	length = strtoll(str, &p, 10);
248ba7f6c2SAl Viro 	switch (c = *p++) {
258ba7f6c2SAl Viro 		case 'b': case 'B':
268ba7f6c2SAl Viro 			if (*p)
27d2fb8b41SHitoshi Mitake 				goto out_err;
2894bdd5edSArnaldo Carvalho de Melo 
2994bdd5edSArnaldo Carvalho de Melo 			__fallthrough;
308ba7f6c2SAl Viro 		case '\0':
318ba7f6c2SAl Viro 			return length;
32d2fb8b41SHitoshi Mitake 		default:
33d2fb8b41SHitoshi Mitake 			goto out_err;
348ba7f6c2SAl Viro 		/* two-letter suffices */
358ba7f6c2SAl Viro 		case 'k': case 'K':
368ba7f6c2SAl Viro 			length <<= 10;
378ba7f6c2SAl Viro 			break;
388ba7f6c2SAl Viro 		case 'm': case 'M':
398ba7f6c2SAl Viro 			length <<= 20;
408ba7f6c2SAl Viro 			break;
418ba7f6c2SAl Viro 		case 'g': case 'G':
428ba7f6c2SAl Viro 			length <<= 30;
438ba7f6c2SAl Viro 			break;
448ba7f6c2SAl Viro 		case 't': case 'T':
458ba7f6c2SAl Viro 			length <<= 40;
46d2fb8b41SHitoshi Mitake 			break;
47d2fb8b41SHitoshi Mitake 	}
488ba7f6c2SAl Viro 	/* we want the cases to match */
498ba7f6c2SAl Viro 	if (islower(c)) {
508ba7f6c2SAl Viro 		if (strcmp(p, "b") != 0)
518ba7f6c2SAl Viro 			goto out_err;
528ba7f6c2SAl Viro 	} else {
538ba7f6c2SAl Viro 		if (strcmp(p, "B") != 0)
548ba7f6c2SAl Viro 			goto out_err;
55d2fb8b41SHitoshi Mitake 	}
568ba7f6c2SAl Viro 	return length;
57d2fb8b41SHitoshi Mitake 
58d2fb8b41SHitoshi Mitake out_err:
598ba7f6c2SAl Viro 	return -1;
60d2fb8b41SHitoshi Mitake }
61e1c01d61SMasami Hiramatsu 
62e1c01d61SMasami Hiramatsu /*
63e1c01d61SMasami Hiramatsu  * Helper function for splitting a string into an argv-like array.
6425985edcSLucas De Marchi  * originally copied from lib/argv_split.c
65e1c01d61SMasami Hiramatsu  */
66e1c01d61SMasami Hiramatsu static const char *skip_sep(const char *cp)
67e1c01d61SMasami Hiramatsu {
68e1c01d61SMasami Hiramatsu 	while (*cp && isspace(*cp))
69e1c01d61SMasami Hiramatsu 		cp++;
70e1c01d61SMasami Hiramatsu 
71e1c01d61SMasami Hiramatsu 	return cp;
72e1c01d61SMasami Hiramatsu }
73e1c01d61SMasami Hiramatsu 
74e1c01d61SMasami Hiramatsu static const char *skip_arg(const char *cp)
75e1c01d61SMasami Hiramatsu {
76e1c01d61SMasami Hiramatsu 	while (*cp && !isspace(*cp))
77e1c01d61SMasami Hiramatsu 		cp++;
78e1c01d61SMasami Hiramatsu 
79e1c01d61SMasami Hiramatsu 	return cp;
80e1c01d61SMasami Hiramatsu }
81e1c01d61SMasami Hiramatsu 
82e1c01d61SMasami Hiramatsu static int count_argc(const char *str)
83e1c01d61SMasami Hiramatsu {
84e1c01d61SMasami Hiramatsu 	int count = 0;
85e1c01d61SMasami Hiramatsu 
86e1c01d61SMasami Hiramatsu 	while (*str) {
87e1c01d61SMasami Hiramatsu 		str = skip_sep(str);
88e1c01d61SMasami Hiramatsu 		if (*str) {
89e1c01d61SMasami Hiramatsu 			count++;
90e1c01d61SMasami Hiramatsu 			str = skip_arg(str);
91e1c01d61SMasami Hiramatsu 		}
92e1c01d61SMasami Hiramatsu 	}
93e1c01d61SMasami Hiramatsu 
94e1c01d61SMasami Hiramatsu 	return count;
95e1c01d61SMasami Hiramatsu }
96e1c01d61SMasami Hiramatsu 
97e1c01d61SMasami Hiramatsu /**
98e1c01d61SMasami Hiramatsu  * argv_free - free an argv
99e1c01d61SMasami Hiramatsu  * @argv - the argument vector to be freed
100e1c01d61SMasami Hiramatsu  *
101e1c01d61SMasami Hiramatsu  * Frees an argv and the strings it points to.
102e1c01d61SMasami Hiramatsu  */
103e1c01d61SMasami Hiramatsu void argv_free(char **argv)
104e1c01d61SMasami Hiramatsu {
105e1c01d61SMasami Hiramatsu 	char **p;
106*a067558eSArnaldo Carvalho de Melo 	for (p = argv; *p; p++) {
107*a067558eSArnaldo Carvalho de Melo 		free(*p);
108*a067558eSArnaldo Carvalho de Melo 		*p = NULL;
109*a067558eSArnaldo Carvalho de Melo 	}
110e1c01d61SMasami Hiramatsu 
111e1c01d61SMasami Hiramatsu 	free(argv);
112e1c01d61SMasami Hiramatsu }
113e1c01d61SMasami Hiramatsu 
114e1c01d61SMasami Hiramatsu /**
115e1c01d61SMasami Hiramatsu  * argv_split - split a string at whitespace, returning an argv
116e1c01d61SMasami Hiramatsu  * @str: the string to be split
117e1c01d61SMasami Hiramatsu  * @argcp: returned argument count
118e1c01d61SMasami Hiramatsu  *
119e1c01d61SMasami Hiramatsu  * Returns an array of pointers to strings which are split out from
120e1c01d61SMasami Hiramatsu  * @str.  This is performed by strictly splitting on white-space; no
121e1c01d61SMasami Hiramatsu  * quote processing is performed.  Multiple whitespace characters are
122e1c01d61SMasami Hiramatsu  * considered to be a single argument separator.  The returned array
123e1c01d61SMasami Hiramatsu  * is always NULL-terminated.  Returns NULL on memory allocation
124e1c01d61SMasami Hiramatsu  * failure.
125e1c01d61SMasami Hiramatsu  */
126e1c01d61SMasami Hiramatsu char **argv_split(const char *str, int *argcp)
127e1c01d61SMasami Hiramatsu {
128e1c01d61SMasami Hiramatsu 	int argc = count_argc(str);
129*a067558eSArnaldo Carvalho de Melo 	char **argv = calloc(argc + 1, sizeof(*argv));
130e1c01d61SMasami Hiramatsu 	char **argvp;
131e1c01d61SMasami Hiramatsu 
132e1c01d61SMasami Hiramatsu 	if (argv == NULL)
133e1c01d61SMasami Hiramatsu 		goto out;
134e1c01d61SMasami Hiramatsu 
135e1c01d61SMasami Hiramatsu 	if (argcp)
136e1c01d61SMasami Hiramatsu 		*argcp = argc;
137e1c01d61SMasami Hiramatsu 
138e1c01d61SMasami Hiramatsu 	argvp = argv;
139e1c01d61SMasami Hiramatsu 
140e1c01d61SMasami Hiramatsu 	while (*str) {
141e1c01d61SMasami Hiramatsu 		str = skip_sep(str);
142e1c01d61SMasami Hiramatsu 
143e1c01d61SMasami Hiramatsu 		if (*str) {
144e1c01d61SMasami Hiramatsu 			const char *p = str;
145e1c01d61SMasami Hiramatsu 			char *t;
146e1c01d61SMasami Hiramatsu 
147e1c01d61SMasami Hiramatsu 			str = skip_arg(str);
148e1c01d61SMasami Hiramatsu 
149e1c01d61SMasami Hiramatsu 			t = strndup(p, str-p);
150e1c01d61SMasami Hiramatsu 			if (t == NULL)
151e1c01d61SMasami Hiramatsu 				goto fail;
152e1c01d61SMasami Hiramatsu 			*argvp++ = t;
153e1c01d61SMasami Hiramatsu 		}
154e1c01d61SMasami Hiramatsu 	}
155e1c01d61SMasami Hiramatsu 	*argvp = NULL;
156e1c01d61SMasami Hiramatsu 
157e1c01d61SMasami Hiramatsu out:
158e1c01d61SMasami Hiramatsu 	return argv;
159e1c01d61SMasami Hiramatsu 
160e1c01d61SMasami Hiramatsu fail:
161e1c01d61SMasami Hiramatsu 	argv_free(argv);
162e1c01d61SMasami Hiramatsu 	return NULL;
163e1c01d61SMasami Hiramatsu }
164bbbb521bSMasami Hiramatsu 
1656964cd2cSMasami Hiramatsu /* Character class matching */
1666964cd2cSMasami Hiramatsu static bool __match_charclass(const char *pat, char c, const char **npat)
1676964cd2cSMasami Hiramatsu {
1686964cd2cSMasami Hiramatsu 	bool complement = false, ret = true;
1696964cd2cSMasami Hiramatsu 
1706964cd2cSMasami Hiramatsu 	if (*pat == '!') {
1716964cd2cSMasami Hiramatsu 		complement = true;
1726964cd2cSMasami Hiramatsu 		pat++;
1736964cd2cSMasami Hiramatsu 	}
1746964cd2cSMasami Hiramatsu 	if (*pat++ == c)	/* First character is special */
1756964cd2cSMasami Hiramatsu 		goto end;
1766964cd2cSMasami Hiramatsu 
1776964cd2cSMasami Hiramatsu 	while (*pat && *pat != ']') {	/* Matching */
1786964cd2cSMasami Hiramatsu 		if (*pat == '-' && *(pat + 1) != ']') {	/* Range */
1796964cd2cSMasami Hiramatsu 			if (*(pat - 1) <= c && c <= *(pat + 1))
1806964cd2cSMasami Hiramatsu 				goto end;
1816964cd2cSMasami Hiramatsu 			if (*(pat - 1) > *(pat + 1))
1826964cd2cSMasami Hiramatsu 				goto error;
1836964cd2cSMasami Hiramatsu 			pat += 2;
1846964cd2cSMasami Hiramatsu 		} else if (*pat++ == c)
1856964cd2cSMasami Hiramatsu 			goto end;
1866964cd2cSMasami Hiramatsu 	}
1876964cd2cSMasami Hiramatsu 	if (!*pat)
1886964cd2cSMasami Hiramatsu 		goto error;
1896964cd2cSMasami Hiramatsu 	ret = false;
1906964cd2cSMasami Hiramatsu 
1916964cd2cSMasami Hiramatsu end:
1926964cd2cSMasami Hiramatsu 	while (*pat && *pat != ']')	/* Searching closing */
1936964cd2cSMasami Hiramatsu 		pat++;
1946964cd2cSMasami Hiramatsu 	if (!*pat)
1956964cd2cSMasami Hiramatsu 		goto error;
1966964cd2cSMasami Hiramatsu 	*npat = pat + 1;
1976964cd2cSMasami Hiramatsu 	return complement ? !ret : ret;
1986964cd2cSMasami Hiramatsu 
1996964cd2cSMasami Hiramatsu error:
2006964cd2cSMasami Hiramatsu 	return false;
2016964cd2cSMasami Hiramatsu }
2026964cd2cSMasami Hiramatsu 
2032a9c8c36SMasami Hiramatsu /* Glob/lazy pattern matching */
20438d14f0cSAndi Kleen static bool __match_glob(const char *str, const char *pat, bool ignore_space,
20538d14f0cSAndi Kleen 			bool case_ins)
206bbbb521bSMasami Hiramatsu {
207bbbb521bSMasami Hiramatsu 	while (*str && *pat && *pat != '*') {
2082a9c8c36SMasami Hiramatsu 		if (ignore_space) {
2092a9c8c36SMasami Hiramatsu 			/* Ignore spaces for lazy matching */
2102a9c8c36SMasami Hiramatsu 			if (isspace(*str)) {
2112a9c8c36SMasami Hiramatsu 				str++;
2122a9c8c36SMasami Hiramatsu 				continue;
2132a9c8c36SMasami Hiramatsu 			}
2142a9c8c36SMasami Hiramatsu 			if (isspace(*pat)) {
2152a9c8c36SMasami Hiramatsu 				pat++;
2162a9c8c36SMasami Hiramatsu 				continue;
2172a9c8c36SMasami Hiramatsu 			}
2182a9c8c36SMasami Hiramatsu 		}
2196964cd2cSMasami Hiramatsu 		if (*pat == '?') {	/* Matches any single character */
220bbbb521bSMasami Hiramatsu 			str++;
221bbbb521bSMasami Hiramatsu 			pat++;
2226964cd2cSMasami Hiramatsu 			continue;
2236964cd2cSMasami Hiramatsu 		} else if (*pat == '[')	/* Character classes/Ranges */
2246964cd2cSMasami Hiramatsu 			if (__match_charclass(pat + 1, *str, &pat)) {
2256964cd2cSMasami Hiramatsu 				str++;
2266964cd2cSMasami Hiramatsu 				continue;
227bbbb521bSMasami Hiramatsu 			} else
2286964cd2cSMasami Hiramatsu 				return false;
2296964cd2cSMasami Hiramatsu 		else if (*pat == '\\') /* Escaped char match as normal char */
2306964cd2cSMasami Hiramatsu 			pat++;
23138d14f0cSAndi Kleen 		if (case_ins) {
23238d14f0cSAndi Kleen 			if (tolower(*str) != tolower(*pat))
233bbbb521bSMasami Hiramatsu 				return false;
23438d14f0cSAndi Kleen 		} else if (*str != *pat)
23538d14f0cSAndi Kleen 			return false;
23638d14f0cSAndi Kleen 		str++;
23738d14f0cSAndi Kleen 		pat++;
238bbbb521bSMasami Hiramatsu 	}
239bbbb521bSMasami Hiramatsu 	/* Check wild card */
240bbbb521bSMasami Hiramatsu 	if (*pat == '*') {
241bbbb521bSMasami Hiramatsu 		while (*pat == '*')
242bbbb521bSMasami Hiramatsu 			pat++;
243bbbb521bSMasami Hiramatsu 		if (!*pat)	/* Tail wild card matches all */
244bbbb521bSMasami Hiramatsu 			return true;
245bbbb521bSMasami Hiramatsu 		while (*str)
24638d14f0cSAndi Kleen 			if (__match_glob(str++, pat, ignore_space, case_ins))
247bbbb521bSMasami Hiramatsu 				return true;
248bbbb521bSMasami Hiramatsu 	}
249bbbb521bSMasami Hiramatsu 	return !*str && !*pat;
250bbbb521bSMasami Hiramatsu }
251bbbb521bSMasami Hiramatsu 
2522a9c8c36SMasami Hiramatsu /**
2532a9c8c36SMasami Hiramatsu  * strglobmatch - glob expression pattern matching
2542a9c8c36SMasami Hiramatsu  * @str: the target string to match
2552a9c8c36SMasami Hiramatsu  * @pat: the pattern string to match
2562a9c8c36SMasami Hiramatsu  *
2572a9c8c36SMasami Hiramatsu  * This returns true if the @str matches @pat. @pat can includes wildcards
2582a9c8c36SMasami Hiramatsu  * ('*','?') and character classes ([CHARS], complementation and ranges are
2592a9c8c36SMasami Hiramatsu  * also supported). Also, this supports escape character ('\') to use special
2602a9c8c36SMasami Hiramatsu  * characters as normal character.
2612a9c8c36SMasami Hiramatsu  *
2622a9c8c36SMasami Hiramatsu  * Note: if @pat syntax is broken, this always returns false.
2632a9c8c36SMasami Hiramatsu  */
2642a9c8c36SMasami Hiramatsu bool strglobmatch(const char *str, const char *pat)
2652a9c8c36SMasami Hiramatsu {
26638d14f0cSAndi Kleen 	return __match_glob(str, pat, false, false);
26738d14f0cSAndi Kleen }
26838d14f0cSAndi Kleen 
26938d14f0cSAndi Kleen bool strglobmatch_nocase(const char *str, const char *pat)
27038d14f0cSAndi Kleen {
27138d14f0cSAndi Kleen 	return __match_glob(str, pat, false, true);
2722a9c8c36SMasami Hiramatsu }
2732a9c8c36SMasami Hiramatsu 
2742a9c8c36SMasami Hiramatsu /**
2752a9c8c36SMasami Hiramatsu  * strlazymatch - matching pattern strings lazily with glob pattern
2762a9c8c36SMasami Hiramatsu  * @str: the target string to match
2772a9c8c36SMasami Hiramatsu  * @pat: the pattern string to match
2782a9c8c36SMasami Hiramatsu  *
2792a9c8c36SMasami Hiramatsu  * This is similar to strglobmatch, except this ignores spaces in
2802a9c8c36SMasami Hiramatsu  * the target string.
2812a9c8c36SMasami Hiramatsu  */
2822a9c8c36SMasami Hiramatsu bool strlazymatch(const char *str, const char *pat)
2832a9c8c36SMasami Hiramatsu {
28438d14f0cSAndi Kleen 	return __match_glob(str, pat, true, false);
2852a9c8c36SMasami Hiramatsu }
286bad03ae4SMasami Hiramatsu 
287bad03ae4SMasami Hiramatsu /**
288bad03ae4SMasami Hiramatsu  * strtailcmp - Compare the tail of two strings
289bad03ae4SMasami Hiramatsu  * @s1: 1st string to be compared
290bad03ae4SMasami Hiramatsu  * @s2: 2nd string to be compared
291bad03ae4SMasami Hiramatsu  *
292bad03ae4SMasami Hiramatsu  * Return 0 if whole of either string is same as another's tail part.
293bad03ae4SMasami Hiramatsu  */
294bad03ae4SMasami Hiramatsu int strtailcmp(const char *s1, const char *s2)
295bad03ae4SMasami Hiramatsu {
296bad03ae4SMasami Hiramatsu 	int i1 = strlen(s1);
297bad03ae4SMasami Hiramatsu 	int i2 = strlen(s2);
298bad03ae4SMasami Hiramatsu 	while (--i1 >= 0 && --i2 >= 0) {
299bad03ae4SMasami Hiramatsu 		if (s1[i1] != s2[i2])
300bad03ae4SMasami Hiramatsu 			return s1[i1] - s2[i2];
301bad03ae4SMasami Hiramatsu 	}
302bad03ae4SMasami Hiramatsu 	return 0;
303bad03ae4SMasami Hiramatsu }
304bad03ae4SMasami Hiramatsu 
305cb1a28a0SArnaldo Carvalho de Melo /**
306ea36c46bSJiri Olsa  * strxfrchar - Locate and replace character in @s
307ea36c46bSJiri Olsa  * @s:    The string to be searched/changed.
308ea36c46bSJiri Olsa  * @from: Source character to be replaced.
309ea36c46bSJiri Olsa  * @to:   Destination character.
310ea36c46bSJiri Olsa  *
311ea36c46bSJiri Olsa  * Return pointer to the changed string.
312ea36c46bSJiri Olsa  */
313ea36c46bSJiri Olsa char *strxfrchar(char *s, char from, char to)
314ea36c46bSJiri Olsa {
315ea36c46bSJiri Olsa 	char *p = s;
316ea36c46bSJiri Olsa 
317ea36c46bSJiri Olsa 	while ((p = strchr(p, from)) != NULL)
318ea36c46bSJiri Olsa 		*p++ = to;
319ea36c46bSJiri Olsa 
320ea36c46bSJiri Olsa 	return s;
321ea36c46bSJiri Olsa }
322ea36c46bSJiri Olsa 
323ea36c46bSJiri Olsa /**
32408aa9cceSNamhyung Kim  * ltrim - Removes leading whitespace from @s.
32508aa9cceSNamhyung Kim  * @s: The string to be stripped.
32608aa9cceSNamhyung Kim  *
32708aa9cceSNamhyung Kim  * Return pointer to the first non-whitespace character in @s.
32808aa9cceSNamhyung Kim  */
32908aa9cceSNamhyung Kim char *ltrim(char *s)
33008aa9cceSNamhyung Kim {
331ecbe5e10SArnaldo Carvalho de Melo 	while (isspace(*s))
33208aa9cceSNamhyung Kim 		s++;
33308aa9cceSNamhyung Kim 
33408aa9cceSNamhyung Kim 	return s;
33508aa9cceSNamhyung Kim }
33608aa9cceSNamhyung Kim 
33708aa9cceSNamhyung Kim /**
338cb1a28a0SArnaldo Carvalho de Melo  * rtrim - Removes trailing whitespace from @s.
339cb1a28a0SArnaldo Carvalho de Melo  * @s: The string to be stripped.
340cb1a28a0SArnaldo Carvalho de Melo  *
341cb1a28a0SArnaldo Carvalho de Melo  * Note that the first trailing whitespace is replaced with a %NUL-terminator
342cb1a28a0SArnaldo Carvalho de Melo  * in the given string @s. Returns @s.
343cb1a28a0SArnaldo Carvalho de Melo  */
344cb1a28a0SArnaldo Carvalho de Melo char *rtrim(char *s)
345cb1a28a0SArnaldo Carvalho de Melo {
346cb1a28a0SArnaldo Carvalho de Melo 	size_t size = strlen(s);
347cb1a28a0SArnaldo Carvalho de Melo 	char *end;
348cb1a28a0SArnaldo Carvalho de Melo 
349cb1a28a0SArnaldo Carvalho de Melo 	if (!size)
350cb1a28a0SArnaldo Carvalho de Melo 		return s;
351cb1a28a0SArnaldo Carvalho de Melo 
352cb1a28a0SArnaldo Carvalho de Melo 	end = s + size - 1;
353cb1a28a0SArnaldo Carvalho de Melo 	while (end >= s && isspace(*end))
354cb1a28a0SArnaldo Carvalho de Melo 		end--;
355cb1a28a0SArnaldo Carvalho de Melo 	*(end + 1) = '\0';
356cb1a28a0SArnaldo Carvalho de Melo 
357cb1a28a0SArnaldo Carvalho de Melo 	return s;
358cb1a28a0SArnaldo Carvalho de Melo }
359b232e073SJiri Olsa 
36093ec4ce7SArnaldo Carvalho de Melo char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
36193ec4ce7SArnaldo Carvalho de Melo {
36293ec4ce7SArnaldo Carvalho de Melo 	/*
36393ec4ce7SArnaldo Carvalho de Melo 	 * FIXME: replace this with an expression using log10() when we
36493ec4ce7SArnaldo Carvalho de Melo 	 * find a suitable implementation, maybe the one in the dvb drivers...
36593ec4ce7SArnaldo Carvalho de Melo 	 *
36693ec4ce7SArnaldo Carvalho de Melo 	 * "%s == %d || " = log10(MAXINT) * 2 + 8 chars for the operators
36793ec4ce7SArnaldo Carvalho de Melo 	 */
36893ec4ce7SArnaldo Carvalho de Melo 	size_t size = nints * 28 + 1; /* \0 */
36993ec4ce7SArnaldo Carvalho de Melo 	size_t i, printed = 0;
37093ec4ce7SArnaldo Carvalho de Melo 	char *expr = malloc(size);
37193ec4ce7SArnaldo Carvalho de Melo 
37293ec4ce7SArnaldo Carvalho de Melo 	if (expr) {
37393ec4ce7SArnaldo Carvalho de Melo 		const char *or_and = "||", *eq_neq = "==";
37493ec4ce7SArnaldo Carvalho de Melo 		char *e = expr;
37593ec4ce7SArnaldo Carvalho de Melo 
37693ec4ce7SArnaldo Carvalho de Melo 		if (!in) {
37793ec4ce7SArnaldo Carvalho de Melo 			or_and = "&&";
37893ec4ce7SArnaldo Carvalho de Melo 			eq_neq = "!=";
37993ec4ce7SArnaldo Carvalho de Melo 		}
38093ec4ce7SArnaldo Carvalho de Melo 
38193ec4ce7SArnaldo Carvalho de Melo 		for (i = 0; i < nints; ++i) {
38293ec4ce7SArnaldo Carvalho de Melo 			if (printed == size)
38393ec4ce7SArnaldo Carvalho de Melo 				goto out_err_overflow;
38493ec4ce7SArnaldo Carvalho de Melo 
38593ec4ce7SArnaldo Carvalho de Melo 			if (i > 0)
386*a067558eSArnaldo Carvalho de Melo 				printed += scnprintf(e + printed, size - printed, " %s ", or_and);
38793ec4ce7SArnaldo Carvalho de Melo 			printed += scnprintf(e + printed, size - printed,
38893ec4ce7SArnaldo Carvalho de Melo 					     "%s %s %d", var, eq_neq, ints[i]);
38993ec4ce7SArnaldo Carvalho de Melo 		}
39093ec4ce7SArnaldo Carvalho de Melo 	}
39193ec4ce7SArnaldo Carvalho de Melo 
39293ec4ce7SArnaldo Carvalho de Melo 	return expr;
39393ec4ce7SArnaldo Carvalho de Melo 
39493ec4ce7SArnaldo Carvalho de Melo out_err_overflow:
39593ec4ce7SArnaldo Carvalho de Melo 	free(expr);
39693ec4ce7SArnaldo Carvalho de Melo 	return NULL;
39793ec4ce7SArnaldo Carvalho de Melo }
398