Commit message: Fix command injection on PDB download (#16966)

* Fix r_sys_mkdirp with absolute path on Windows
* Fix build with --with-openssl
* Use RBuffer in r_socket_http_answer()
* r_socket_http_answer: Fix read for big responses
* Implement r_str_escape_sh()
* Cleanup r_socket_connect() on Windows
* Fix socket being created without a protocol
* Fix socket connect with SSL ##socket
* Use select() in r_socket_ready()
* Fix read failing if received only protocol answer
* Fix double-free
* r_socket_http_get: Fail if req. SSL with no support
* Follow redirects in r_socket_http_answer()
* Fix r_socket_http_get result length with R2_CURL=1
* Also follow redirects
* Avoid using curl for downloading PDBs
* Use r_socket_http_get() on UNIXs
* Use WinINet API on Windows for r_socket_http_get()
* Fix command injection
* Fix r_sys_cmd_str_full output for binary data
* Validate GUID on PDB download
* Pass depth to socket_http_get_recursive()
* Remove 'r_' and '__' from static function names
* Fix is_valid_guid
* Fix for comments
CVE: CVE-2020-15121
CWE: CWE-78
Vulnerability description: In radare2 before version 4.5.0, malformed PDB file names in the PDB server path cause shell injection. To trigger the problem it's required to open the executable in radare2 and run idpd to trigger the download. The shell code will execute, and will create a file called pwned in the current directory.

Project: radare2
File: socket.c

R_API RSocket *r_socket_accept_timeout(RSocket *s, unsigned int timeout) {
	fd_set read_fds;
	fd_set except_fds;

	FD_ZERO (&read_fds);
	FD_SET (s->fd, &read_fds);

	FD_ZERO (&except_fds);
	FD_SET (s->fd, &except_fds);

	struct timeval t = {timeout, 0};

	int r = select (s->fd + 1, &read_fds, NULL, &except_fds, &t);
	if(r < 0) {
		perror ("select");
	} else if (r > 0 && FD_ISSET (s->fd, &read_fds)) {
		return r_socket_accept (s);
	}

	return NULL;
}

Project: radare2
File: str.c

R_API char *r_str_list_join(RList *str, const char *sep) {
	RStrBuf *sb = r_strbuf_new ("");
	const char *p;
	while ((p = r_list_pop_head (str))) {
		if (r_strbuf_length (sb) != 0) {
			r_strbuf_append (sb, sep);
		}
		r_strbuf_append (sb, p);
	}
	return r_strbuf_drain (sb);
}

Project: radare2
File: str.c

R_API char *r_str_sanitize_sdb_key(const char *s) {
	if (!s || !*s) {
		return NULL;
	}
	size_t len = strlen (s);
	char *ret = malloc (len + 1);
	if (!ret) {
		return NULL;
	}
	char *cur = ret;
	while (len > 0) {
		char c = *s;
		if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9')
			&& c != '_' && c != ':') {
			c = '_';
		}
		*cur = c;
		s++;
		cur++;
		len--;
	}
	*cur = '\0';
	return ret;
}

Project: radare2
File: str.c

R_API const char *r_str_get2(const char *str) {
	return str? str: nullstr;
}

Project: radare2
File: sys.c

R_API void r_sys_info_free(RSysInfo *si) {
	free (si->sysname);
	free (si->nodename);
	free (si->release);
	free (si->version);
	free (si->machine);
	free (si);
}

Project: radare2
File: str.c

R_API void r_str_uri_decode(char *s) {
	int n;
	char *d;
	for (d = s; *s; s++, d++) {
		if (*s == '%') {
			sscanf (s + 1, "%02x", &n);
			*d = n;
			s += 2;
		} else {
			*d = *s;
		}
	}
	*d = 0;
}

Project: radare2
File: str.c

R_API char *r_str_new(const char *str) {
	return str? strdup (str): NULL;
}

Project: radare2
File: test_str.c

bool test_r_str_split(void) {
	char* hi = strdup ("hello world");
	int r = r_str_split (hi, ' ');
	mu_assert_eq (r, 2, "split on space");
	char* hello = hi;
	char* world = hi + 6;
	mu_assert_streq (hello, "hello", "first string in split");
	mu_assert_streq (world, "world", "second string in split");
	free (hi);
	mu_end;
}

Project: radare2
File: sys.c

R_API int r_sys_clearenv(void) {
#if __UNIX__
#if __APPLE__ && !HAVE_ENVIRON
	/* do nothing */
	if (!env) {
		env = r_sys_get_environ ();
		return 0;
	}
	if (env) {
		char **e = env;
		while (*e) {
			*e++ = NULL;
		}
	}
#else
	if (!environ) {
		return 0;
	}
	while (*environ) {
		*environ++ = NULL;
	}
#endif
	return 0;
#else
#ifdef _MSC_VER
#pragma message ("r_sys_clearenv : unimplemented for this platform")
#else
#warning r_sys_clearenv : unimplemented for this platform
#endif
	return 0;
#endif
}

Project: radare2
File: socket.c

R_API ut8* r_socket_slurp(RSocket *s, int *len) {
	return NULL;
}

Project: radare2
File: socket.c

R_API int r_socket_write(RSocket *s, void *buf, int len) {
	return -1;
}

Project: radare2
File: disk.c

SDB_API int sdb_disk_insert(Sdb* s, const char *key, const char *val) {
	struct cdb_make *c = &s->m;
	if (!key || !val) {
		return 0;
	}
	//if (!*val) return 0; //undefine variable if no value
	return cdb_make_add (c, key, strlen (key), val, strlen (val));
}

Project: radare2
File: sys.c

R_API ut64 r_sys_now(void) {
	ut64 ret;
	struct timeval now;
	gettimeofday (&now, NULL);
	ret = now.tv_sec;
	ret <<= 20;
	ret |= now.tv_usec;
	//(sizeof (now.tv_sec) == 4
	return ret;
}

Project: radare2
File: test_str.c

bool test_r_str_newf(void) {
	char *a = r_str_newf ("hello");
	mu_assert_streq (a, "hello", "oops");
	free (a);

	a = r_str_newf ("%s/%s", "hello", "world");
	mu_assert_streq (a, "hello/world", "oops");
	free (a);

	a = r_str_newf ("%s/%s", "hello", "world");
	a = r_str_appendf (a, "..%s/%s", "cow", "low");
	a = r_str_appendf (a, "PWN");
	mu_assert_streq (a, "hello/world..cow/lowPWN", "oops");
	free (a);
	mu_end;
}

Project: radare2
File: str.c

R_API void r_str_reverse(char *str) {
	int i, len = strlen (str);
	int half = len / 2;
	for (i = 0; i < half; i++) {
		char ch = str[i];
		str[i] = str[len - i - 1];
		str[len - i - 1] = ch;
	}
}

Project: radare2
File: str.c

R_API char *r_str_append_owned(char *ptr, char *string) {
	if (!ptr) {
		return string;
	}
	char *r = r_str_append(ptr, string);
	free (string);
	return r;
}

Project: radare2
File: test_str.c

bool all_tests () {
	mu_run_test (test_r_str_newf);
	mu_run_test (test_r_str_replace_char_once);
	mu_run_test (test_r_str_replace_char);
	mu_run_test (test_r_str_replace);
	mu_run_test (test_r_str_bits64);
	mu_run_test (test_r_str_rwx);
	mu_run_test (test_r_str_rwx_i);
	mu_run_test (test_r_str_bool);
	mu_run_test (test_r_str_trim);
	mu_run_test (test_r_str_case);
	mu_run_test (test_r_str_split);
	mu_run_test (test_r_str_tokenize);
	mu_run_test (test_r_str_char_count);
	mu_run_test (test_r_str_word_count);
	mu_run_test (test_r_str_ichr);
	mu_run_test (test_r_str_lchr);
	mu_run_test (test_r_sub_str_lchr);
	mu_run_test (test_r_sub_str_rchr);
	mu_run_test (test_r_str_rchr);
	mu_run_test (test_r_str_ansi_len);
	mu_run_test (test_r_str_len_utf8_ansi);
	mu_run_test (test_r_str_utf8_charsize);
	mu_run_test (test_r_str_utf8_charsize_prev);
	mu_run_test (test_r_str_sanitize_sdb_key);
	mu_run_test (test_r_str_escape_sh);
	mu_run_test (test_r_str_unescape);
	mu_run_test (test_r_str_constpool);
	mu_run_test (test_r_str_format_msvc_argv);
	mu_run_test (test_r_str_str_xy);
	return tests_passed != tests_run;
}

Project: radare2
File: str.c

R_API void r_str_range_foreach(const char *r, RStrRangeCallback cb, void *u) {
	const char *p = r;
	for (; *r; r++) {
		if (*r == ',') {
			cb (u, atoi (p));
			p = r + 1;
		}
		if (*r == '-') {
			if (p != r) {
				int from = atoi (p);
				int to = atoi (r + 1);
				for (; from <= to; from++) {
					cb (u, from);
				}
			} else {
				fprintf (stderr, "Invalid range\n");
			}
			for (r++; *r && *r != ',' && *r != '-'; r++) {
				;
			}
			p = r;
		}
	}
	if (*p) {
		cb (u, atoi (p));
	}
}

Project: radare2
File: sys.c

R_API int r_sys_signal(int sig, void (*handler) (int)) {
	int s[2] = { sig, 0 };
	return r_sys_sigaction (s, handler);
}

Project: radare2
File: socket.c

R_API RSocket *r_socket_new(bool is_ssl) {
	RSocket *s = R_NEW0 (RSocket);
	if (!s) {
		return NULL;
	}
	s->is_ssl = is_ssl;
	s->port = 0;
#if __UNIX_
	r_sys_signal (SIGPIPE, SIG_IGN);
#endif
	s->local = 0;
	s->fd = R_INVALID_SOCKET;
#if HAVE_LIB_SSL
	if (is_ssl) {
		s->sfd = NULL;
		s->ctx = NULL;
		s->bio = NULL;
#if OPENSSL_VERSION_NUMBER < 0x1010000fL
		if (!SSL_library_init ()) {
			r_socket_free (s);
			return NULL;
		}
		SSL_load_error_strings ();
#endif
	}
#endif
	return s;
}

Project: radare2
File: sys.c

R_API int r_sys_sleep(int secs) {
#if HAS_CLOCK_NANOSLEEP
	struct timespec rqtp;
	rqtp.tv_sec = secs;
	rqtp.tv_nsec = 0;
	return clock_nanosleep (CLOCK_MONOTONIC, 0, &rqtp, NULL);
#elif __UNIX__
	return sleep (secs);
#else
	Sleep (secs * 1000); // W32
	return 0;
#endif
}

Project: radare2
File: sys.c

R_API char **r_sys_get_environ () {
#if __APPLE__ && !HAVE_ENVIRON
	env = *_NSGetEnviron();
#else
	env = environ;
#endif
	// return environ if available??
	if (!env) {
		env = r_lib_dl_sym (NULL, "environ");
	}
	return env;
}

Project: radare2
File: str.c

R_API const char *r_str_bool(int b) {
	return b? "true": "false";
}

Project: radare2
File: socket.c

R_API RSocket *r_socket_new_from_fd(int fd) {
	RSocket *s = R_NEW0 (RSocket);
	if (s) {
		s->fd = fd;
	}
	return s;
}

Project: radare2
File: pdb_downloader.c

int r_bin_pdb_download(RCore *core, int isradjson, int *actions_done, SPDBOptions *options) {
	int ret;
	SPDBDownloaderOpt opt;
	SPDBDownloader pdb_downloader;
	RBinInfo *info = r_bin_get_info (core->bin);

	if (!info || !info->debug_file_name) {
		eprintf ("Can't find debug filename\n");
		return 1;
	}

	if (!is_valid_guid (info->guid)) {
		eprintf ("Invalid GUID for file\n");
		return 1;
	}

	if (!options || !options->symbol_server || !options->user_agent) {
		eprintf ("Can't retrieve pdb configurations\n");
		return 1;
	}

	opt.dbg_file = (char*) r_file_basename (info->debug_file_name);
	opt.guid = info->guid;
	opt.symbol_server = options->symbol_server;
	opt.user_agent = options->user_agent;
	opt.symbol_store_path = options->symbol_store_path;
	opt.extract = options->extract;

	init_pdb_downloader (&opt, &pdb_downloader);
	ret = pdb_downloader.download ? pdb_downloader.download (&pdb_downloader) : 0;
	if (isradjson && actions_done) {
		printf ("%s\"pdb\":{\"file\":\"%s\",\"download\":%s}",
		        *actions_done ? "," : "", opt.dbg_file, ret ? "true" : "false");
	} else {
		printf ("PDB \"%s\" download %s\n",
		        opt.dbg_file, ret ? "success" : "failed");
	}
	if (actions_done) {
		(*actions_done)++;
	}
	deinit_pdb_downloader (&pdb_downloader);

	return 0;
}

Project: radare2
File: str.c

R_API char *r_str_crop(const char *str, unsigned int x, unsigned int y,
		unsigned int x2, unsigned int y2) {
	char *r, *ret;
	unsigned int ch = 0, cw = 0;
	if (x2 < 1 || y2 < 1 || !str) {
		return strdup ("");
	}
	r = ret = strdup (str);
	while (*str) {
		/* crop height */
		if (ch >= y2) {
			r--;
			break;
		}

		if (*str == '\n') {
			if (ch >= y && ch < y2) {
				*r++ = *str;
			}
			str++;
			ch++;
			cw = 0;
		} else {
			if (ch >= y && ch < y2 && cw >= x && cw < x2) {
				*r++ = *str;
			}
			/* crop width */
			/* skip until newline */
			if (cw >= x2) {
				while (*str && *str != '\n') {
					str++;
				}
			} else {
				str++;
			}
			cw++;
		}
	}
	*r = 0;
	return ret;
}

Project: radare2
File: str.c

R_API int r_str_word_set0_stack(char *str) {
	int i;
	char *p, *q;
	RStack *s;
	void *pop;
	if (!str || !*str) {
		return 0;
	}
	for (i = 0; str[i] && str[i+1]; i++) {
		if (i > 0 && str[i - 1] == ' ' && str[i] == ' ') {
			memmove (str + i, str + i + 1, strlen (str + i));
			i--;
		}
		if (i == 0 && str[i] == ' ') {
			memmove (str + i, str + i + 1, strlen (str + i));
		}
	}
	if (str[i] == ' ') {
		str[i] = 0;
	}
	s = r_stack_new (5); //Some random number
	for (i = 1, p = str; *p; p++) {
		q = p - 1;
		if (p > str && (*q == '\\')) {
			memmove (q, p, strlen (p) + 1);
			p--;
			continue;
		}
		switch (*p) {
		case '(':
		case '{':
		case '[':
			r_stack_push (s, (void *)p);
			continue;
		case '\'':
		case '"':
			pop = r_stack_pop (s);
			if (pop && *(char *)pop != *p) {
				r_stack_push (s, pop);
				r_stack_push (s, (void *)p);
			} else if (!pop) {
				r_stack_push (s, (void *)p);
			}
			continue;
		case ')':
		case '}':
		case ']':
			pop = r_stack_pop (s);
			if (pop) {
				if ((*(char *)pop == '(' && *p == ')') ||
					(*(char *)pop == '{' && *p == '}') ||
					(*(char *)pop == '[' && *p == ']')) {
					continue;
				}
			}
			break;
		case ' ':
			if (p > str && !*q) {
				memmove (p, p+1, strlen (p + 1) + 1);
				if (*q == '\\') {
					*q = ' ';
					continue;
				}
				p--;
			}
			if (r_stack_is_empty (s)) {
				i++;
				*p = '\0';
			}
		default:
			break;
		}
	}
	r_stack_free (s);
	return i;
}

Project: radare2
File: str.c

R_API void r_str_sanitize(char *c) {
	char *d = c;
	if (d)  {
		for (; *d; c++, d++) {
			switch (*d) {
			case '`':
			case '$':
			case '{':
			case '}':
			case '~':
			case '|':
			case ';':
			case '#':
			case '@':
			case '&':
			case '<':
			case '>':
				*c = '_';
				continue;
			}
		}
	}
}

Project: radare2
File: test_str.c

int main(int argc, char **argv) {
	return all_tests();
}

Project: radare2
File: sys.c

R_API int r_sys_run(const ut8 *buf, int len) {
	const int sz = 4096;
	int pdelta, ret, (*cb)();
#if USE_FORK
	int st, pid;
#endif
// TODO: define R_SYS_ALIGN_FORWARD in r_util.h
	ut8 *ptr, *p = malloc ((sz + len) << 1);
	ptr = p;
	pdelta = ((size_t)(p)) & (4096 - 1);
	if (pdelta) {
		ptr += (4096 - pdelta);
	}
	if (!ptr || !buf) {
		eprintf ("r_sys_run: Cannot run empty buffer\n");
		free (p);
		return false;
	}
	memcpy (ptr, buf, len);
	r_mem_protect (ptr, sz, "rx");
	//r_mem_protect (ptr, sz, "rwx"); // try, ignore if fail
	cb = (int (*)())ptr;
#if USE_FORK
#if __UNIX__
	pid = r_sys_fork ();
#else
	pid = -1;
#endif
	if (pid < 0) {
		return cb ();
	}
	if (!pid) {
		ret = cb ();
		exit (ret);
		return ret;
	}
	st = 0;
	waitpid (pid, &st, 0);
	if (WIFSIGNALED (st)) {
		int num = WTERMSIG(st);
		eprintf ("Got signal %d\n", num);
		ret = num;
	} else {
		ret = WEXITSTATUS (st);
	}
#else
	ret = (*cb) ();
#endif
	free (p);
	return ret;
}

Project: radare2
File: test_str.c

bool test_r_str_case(void) {
	char* str1_mixedcase = strdup ("mIxEdCaSe");
	char* str2_mixedcase = strdup ("mIxEdCaSe");
	r_str_case (str1_mixedcase, true /*upcase*/);
	r_str_case (str2_mixedcase, false /*downcase*/);
	mu_assert_streq (str1_mixedcase, "MIXEDCASE", "upcase");
	mu_assert_streq (str2_mixedcase, "mixedcase", "downcase");
	char* non_alphanum_1 = strdup ("c00lstring!");
	char* non_alphanum_2 = strdup ("c00lstrinG!");
	r_str_case (non_alphanum_1, true /*upcase*/);
	r_str_case (non_alphanum_2, false /*downcase*/);
	mu_assert_streq (non_alphanum_1, "C00LSTRING!", "upcase, nonalpanum");
	mu_assert_streq (non_alphanum_2, "c00lstring!", "downcase, nonalpanum");
	free (str1_mixedcase);
	free (str2_mixedcase);
	free (non_alphanum_1);
	free (non_alphanum_2);
	mu_end;
}

Project: radare2
File: pdb_downloader.c

static int download(struct SPDBDownloader *pd) {
	SPDBDownloaderOpt *opt = pd->opt;
	int res = 0;
	int cmd_ret;

	if (!opt->dbg_file || !*opt->dbg_file) {
		// no pdb debug file
		return 0;
	}

	char *abspath_to_file = r_str_newf ("%s%s%s%s%s%s%s",
		opt->symbol_store_path, R_SYS_DIR,
		opt->dbg_file, R_SYS_DIR,
		opt->guid, R_SYS_DIR,
		opt->dbg_file);

	if (r_file_exists (abspath_to_file)) {
		eprintf ("File already downloaded.\n");
		free (abspath_to_file);
		return 1;
	}

	if (checkExtract () || opt->extract == 0) {
		char *extractor_cmd = NULL;
		char *archive_name = strdup (opt->dbg_file);
		archive_name[strlen (archive_name) - 1] = '_';
		char *abspath_to_archive = r_str_newf ("%s%s%s%s%s%s%s",
			opt->symbol_store_path, R_SYS_DIR,
			opt->dbg_file, R_SYS_DIR,
			opt->guid, R_SYS_DIR,
			archive_name);

		eprintf ("Attempting to download compressed pdb in %s\n", abspath_to_archive);
		char *abs_arch_esc = r_str_escape_sh (abspath_to_archive);
#if __WINDOWS__
		char *abs_file_esc = r_str_escape_sh (abspath_to_file);
		// expand %1 %2
		// %1 - absolute path to archive
		// %2 - absolute path to file that will be dearchive
		extractor_cmd = r_str_newf ("expand \"%s\" \"%s\"", abs_arch_esc, abs_file_esc);
		free (abs_file_esc);
#else
		char *abspath_to_dir = r_file_dirname (abspath_to_archive);
		char *abs_dir_esc = r_str_escape_sh (abspath_to_dir);
		// cabextract -d %1 %2
		// %1 - path to directory where to extract all files from cab archive
		// %2 - absolute path to cab archive
		extractor_cmd = r_str_newf ("cabextract -d \"%s\" \"%s\"", abs_arch_esc, abs_dir_esc);
		free (abs_dir_esc);
		free (abspath_to_dir);
#endif
		free (abs_arch_esc);
		res = download_and_write (opt, archive_name);

		if (opt->extract > 0 && res) {
			eprintf ("Attempting to decompress pdb\n");
			if (res && ((cmd_ret = r_sys_cmd (extractor_cmd)) != 0)) {
				eprintf ("cab extractor exited with error %d\n", cmd_ret);
				res = 0;
			}
			r_file_rm (abspath_to_archive);
		}
		free (archive_name);
		free (abspath_to_archive);
	}
	if (res == 0) {
		eprintf ("Falling back to uncompressed pdb\n");
		eprintf ("Attempting to download uncompressed pdb in %s\n", abspath_to_file);
		res = download_and_write (opt, opt->dbg_file);
	}
	free (abspath_to_file);
	return res;
}

Project: radare2
File: test_str.c

bool test_r_sub_str_lchr(void) {
	const char* test = "raddddare2d";
	const char* out = r_sub_str_lchr (test, 1, 8, 'd');
	mu_assert_streq (out, "dare2d", "pointer to last d in range in radddddare2d");
	mu_end;
}

Project: radare2
File: str.c

R_API int r_str_cmp(const char *a, const char *b, int len) {
	if ((a == b) || (!a && !b)) {
		return 0;
	}
	if (!a && b) {
		return -1;
	}
	if (a && !b) {
		return 1;
	}
	if (len < 0) {
		return strcmp (a, b);
	}
	return strncmp (a, b, len);
}

Project: radare2
File: str.c

static char *r_str_escape_(const char *buf, int dot_nl, bool parse_esc_seq, bool ign_esc_seq, bool show_asciidot, bool esc_bslash) {
	r_return_val_if_fail (buf, NULL);

	/* Worst case scenario, we convert every byte to a single-char escape
	 * (e.g. \n) if show_asciidot, or \xhh if !show_asciidot */
	char *new_buf = malloc (1 + strlen (buf) * (show_asciidot ? 2 : 4));
	if (!new_buf) {
		return NULL;
	}
	const char *p = buf;
	char *q = new_buf;
	while (*p) {
		switch (*p) {
		case 0x1b: // ESC
			if (parse_esc_seq) {
				const char *start_seq = p;
				p++;
				/* Parse the ANSI code (only the graphic mode
				 * set ones are supported) */
				if (*p == '\0') {
					goto out;
				}
				if (*p == '[') {
					for (p++; *p != 'm'; p++) {
						if (*p == '\0') {
							goto out;
						}
					}
					if (!ign_esc_seq) {
						memcpy (q, start_seq, p - start_seq + 1);
						q += (p - start_seq + 1);
					}
				}
				break;
			}
			/* fallthrough */
		default:
			r_str_byte_escape (p, &q, dot_nl, show_asciidot, esc_bslash);
		}
		p++;
	}
out:
	*q = '\0';
	return new_buf;
}

Project: radare2
File: socket_http.c

static char *socket_http_answer(RSocket *s, int *code, int *rlen, ut32 redirections) {
	r_return_val_if_fail (s, NULL);
	const char *p;
	int ret, len = 0, delta = 0;
	char *dn;
	RBuffer *b = r_buf_new ();
	if (!b) {
		return NULL;
	}
	char *res = NULL;
	size_t olen = socket_slurp (s, b);
	char *buf = malloc (olen + 1);
	if (!buf) {
		goto exit;
	}
	r_buf_read_at (b, 0, (ut8 *)buf, olen);
	buf[olen] = 0;
	if ((dn = (char*)r_str_casestr (buf, "\n\n"))) {
		delta += 2;
	} else if ((dn = (char*)r_str_casestr (buf, "\r\n\r\n"))) {
		delta += 4;
	} else {
		goto exit;
	}

	olen -= delta;
	*dn = 0; // chop headers

	/* Follow redirects */
	p = r_str_casestr (buf, "Location:");
	if (p) {
		if (!redirections) {
			eprintf ("Too many redirects\n");
			goto exit;
		}
		p += strlen ("Location:");
		char *end_url = strchr (p, '\n');
		if (end_url) {
			int url_len = end_url - p;
			char *url = r_str_ndup (p, url_len);
			r_str_trim (url);
			res = socket_http_get_recursive (url, code, rlen, --redirections);
			free (url);
			len = *rlen;
		}
		goto exit;
	}

	/* Parse Len */
	p = r_str_casestr (buf, "Content-Length: ");
	if (p) {
		len = atoi (p + 16);
	} else {
		len = olen - (dn - buf);
	}
	if (len > 0) {
		if (len > olen) {
			res = malloc (len + 2);
			if (!res) {
				goto exit;
			}
			olen -= dn - buf;
			memcpy (res, dn + delta, olen);
			do {
				ret = r_socket_read_block (s, (ut8*) res + olen, len - olen);
				if (ret < 1) {
					break;
				}
				olen += ret;
			} while (olen < len);
			res[len] = 0;
		} else {
			res = malloc (len + 1);
			if (res) {
				memcpy (res, dn + delta, len);
				res[len] = 0;
			}
		}
	} else {
		res = NULL;
	}
exit:
	free (buf);
	r_buf_free (b);
	r_socket_close (s);
	if (rlen) {
		*rlen = len;
	}
	return res;
}

Project: radare2
File: sys.c

R_API int r_sys_chdir(const char *s) {
	return r_sandbox_chdir (s)==0;
}

Project: radare2
File: str.c

R_API size_t r_str_ansi_len(const char *str) {
	return r_str_ansi_nlen (str, 0);
}

Project: radare2
File: test_str.c

bool test_r_str_tokenize(void) {
	//XXX r_str_word0 doesn't work on "hello      world" to
	// tokenize into ["hello", "world"]
	char* hi = strdup ("hello world");
	int r = r_str_word_set0 (hi);
	mu_assert_eq (r, 2, "tokenize hello world");
	const char* hello = r_str_word_get0 (hi, 0);
	const char* world = r_str_word_get0 (hi, 1);
	mu_assert_streq (hello, "hello", "first string in split");
	mu_assert_streq (world, "world", "second string in split");
	free (hi);
	mu_end;
}

Project: radare2
File: socket.c

R_API int r_socket_close (RSocket *s) {
	return -1;
}

Project: radare2
File: disk.c

SDB_API bool sdb_disk_finish (Sdb* s) {
	bool reopen = false, ret = true;
	IFRET (!cdb_make_finish (&s->m));
#if USE_MMAN
	IFRET (fsync (s->fdump));
#endif
	IFRET (close (s->fdump));
	s->fdump = -1;
	// close current fd to avoid sharing violations
	if (s->fd != -1) {
		close (s->fd);
		s->fd = -1;
		reopen = true;
	}
#if __SDB_WINDOWS__
	LPTSTR ndump_ = r_sys_conv_utf8_to_utf16 (s->ndump);
	LPTSTR dir_ = r_sys_conv_utf8_to_utf16 (s->dir);

	if (MoveFileEx (ndump_, dir_, MOVEFILE_REPLACE_EXISTING)) {
		//eprintf ("Error 0x%02x\n", GetLastError ());
	}
	free (ndump_);
	free (dir_);
#else
	if (s->ndump && s->dir) {
		IFRET (rename (s->ndump, s->dir));
	}
#endif
	free (s->ndump);
	s->ndump = NULL;
	// reopen if was open before
	reopen = true; // always reopen if possible
	if (reopen) {
		int rr = sdb_open (s, s->dir);
		if (ret && rr < 0) {
			ret = false;
		}
		cdb_init (&s->db, s->fd);
	}
	return ret;
}

Project: radare2
File: str.c

R_API int r_str_casecmp(const char *s1, const char *s2) {
#ifdef _MSC_VER
	return stricmp (s1, s2);
#else
	return strcasecmp (s1, s2);
#endif
}

Project: radare2
File: test_str.c

bool test_r_str_utf8_charsize_prev(void) {
	char s[16] = "\x61\xc3\xa1\xe6\x97\xa5\xf0\x9f\x91\x8c\xf0\x9f\x91\x8c\x8c"; // aá日👌
	int sz;

	sz = r_str_utf8_charsize_last (s);
	mu_assert_eq (sz, 0, "Malformed UTF-8");

	sz = r_str_utf8_charsize_prev (s + 10, 10);
	mu_assert_eq (sz, 4, "4 byte UTF-8");

	sz = r_str_utf8_charsize_prev (s + 6, 6);
	mu_assert_eq (sz, 3, "3 byte UTF-8");

	sz = r_str_utf8_charsize_prev (s + 3, 3);
	mu_assert_eq (sz, 2, "2 byte UTF-8");

	sz = r_str_utf8_charsize_prev (s + 1, 1);
	mu_assert_eq (sz, 1, "1 byte UTF-8");

	mu_end;
}

Project: radare2
File: socket.c

R_API bool r_socket_listen(RSocket *s, const char *port, const char *certfile) {
	int optval = 1;
	int ret;
	struct linger linger = { 0 };

	if (s->proto == R_SOCKET_PROTO_UNIX) {
#if __UNIX__
		return __listen_unix (s, port);
#endif
		return false;
	}

	if (r_sandbox_enable (0)) {
		return false;
	}
#if __WINDOWS__
	WSADATA wsadata;
	if (WSAStartup (MAKEWORD (1, 1), &wsadata) == SOCKET_ERROR) {
		eprintf ("Error creating socket.");
		return false;
	}
#endif
	if ((s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == R_INVALID_SOCKET) {
		return false;
	}

	linger.l_onoff = 1;
	linger.l_linger = 1;
	ret = setsockopt (s->fd, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof (linger));
	if (ret < 0) {
		return false;
	}
	{ // fix close after write bug //
	int x = 1500; // FORCE MTU
	ret = setsockopt (s->fd, SOL_SOCKET, SO_SNDBUF, (void*)&x, sizeof (int));
	if (ret < 0) {
		return false;
	}
	}
	ret = setsockopt (s->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof optval);
	if (ret < 0) {
		return false;
	}

	memset (&s->sa, 0, sizeof (s->sa));
	s->sa.sin_family = AF_INET;
	s->sa.sin_addr.s_addr = htonl (s->local? INADDR_LOOPBACK: INADDR_ANY);
	s->port = r_socket_port_by_name (port);
	if (s->port < 1) {
		return false;
	}
	s->sa.sin_port = htons (s->port); // TODO honor etc/services
	if (bind (s->fd, (struct sockaddr *)&s->sa, sizeof (s->sa)) < 0) {
		r_sys_perror ("bind");
#ifdef _MSC_VER
		closesocket (s->fd);
#else
		close (s->fd);
#endif
		return false;
	}
#if __UNIX__
	r_sys_signal (SIGPIPE, SIG_IGN);
#endif
	if (listen (s->fd, 32) < 0) {
#ifdef _MSC_VER
		closesocket (s->fd);
#else
		close (s->fd);
#endif
		return false;
	}
#if HAVE_LIB_SSL
	if (s->is_ssl) {
		s->ctx = SSL_CTX_new (SSLv23_method ());
		if (!s->ctx) {
			r_socket_free (s);
			return false;
		}
		if (!SSL_CTX_use_certificate_chain_file (s->ctx, certfile)) {
			r_socket_free (s);
			return false;
		}
		if (!SSL_CTX_use_PrivateKey_file (s->ctx, certfile, SSL_FILETYPE_PEM)) {
			r_socket_free (s);
			return false;
		}
		SSL_CTX_set_verify_depth (s->ctx, 1);
	}
#endif
	return true;
}

Project: radare2
File: str.c

R_API size_t r_str_len_utf8(const char *s) {
	size_t i = 0, j = 0, fullwidths = 0;
	while (s[i]) {
		if ((s[i] & 0xc0) != 0x80) {
			j++;
			if (r_str_char_fullwidth (s + i, 4)) {
				fullwidths++;
			}
		}
		i++;
	}
	return j + fullwidths;
}

Project: radare2
File: socket.c

R_API int r_socket_free (RSocket *s) {
	return -1;
}

Project: radare2
File: socket.c

R_API int r_socket_free(RSocket *s) {
	int res = r_socket_close (s);
#if HAVE_LIB_SSL
	if (s && s->is_ssl) {
		if (s->sfd) {
			SSL_free (s->sfd);
		}
		if (s->ctx) {
			SSL_CTX_free (s->ctx);
		}
	}
#endif
	free (s);
	return res;
}

Project: radare2
File: str.c

R_API char *r_str_escape_latin1(const char *buf, bool show_asciidot, bool esc_bslash, bool colors) {
	return r_str_escape_ (buf, false, colors, !colors, show_asciidot, esc_bslash);
}

Project: radare2
File: str.c

R_API char *r_str_trunc_ellipsis(const char *str, int len) {
	if (!str) {
		return NULL;
	}
	if (strlen (str) < len) {
		return strdup (str);
	}
	char *buf = r_str_newlen (str, len);
	if (buf && len > 4) {
		strcpy (buf + len - 4, "...");
	}
	return buf;
}

Project: radare2
File: str.c

R_API bool r_str_ccmp(const char *dst, const char *src, int ch) {
	int i;
	for (i = 0; src[i] && src[i] != ch; i++) {
		if (dst[i] != src[i]) {
			return true;
		}
	}
	return false;
}

Project: radare2
File: str.c

static int strncmp_skip_color_codes(const char *s1, const char *s2, int n) {
	int i = 0, j = 0;
	int count = 0;
	for (i = 0, j = 0; s1[i]  && s2[j] && count < n; i++, j++, count++) {
		while (s1[i] == 0x1b) {
			while (s1[i] && s1[i] != 'm') {
				i++;
			}
			if (s1[i]) {
				i++;
			}
		}
		while (s2[j] == 0x1b) {
			while (s2[j] && s2[j] != 'm') {
				j++;
			}
			if (s2[j]) {
				j++;
			}
		}
		if (s1[i] != s2[j]) {
			return -1;
		}
	}

	if (count < n && s1[i] != s2[j]) {
		return -1;
	}

	return 0;
}

Project: radare2
File: str.c

R_API bool r_str_is_printable_incl_newlines(const char *str) {
	while (*str) {
		int ulen = r_utf8_decode ((const ut8*)str, strlen (str), NULL);
		if (ulen > 1) {
			str += ulen;
			continue;
		}
		if (!IS_PRINTABLE (*str)) {
			if (*str != '\r' && *str != '\n' && *str != '\t') {
				return false;
			}
		}
		str++;
	}
	return true;
}

Project: radare2
File: str.c

R_API const char *r_str_nstr(const char *s, const char *find, int slen) {
	char c, sc;
	size_t len;

	if ((c = *find++) != '\0') {
		len = strlen (find);
		do {
			do {
				if (slen-- < 1 || !(sc = *s++)) {
					return NULL;
				}
			} while (sc != c);
			if (len > slen) {
				return NULL;
			}
		} while (strncmp (s, find, len) != 0);
		s--;
	}
	return (char *)s;
}

Project: radare2
File: sys.c

R_API bool r_sys_tts(const char *txt, bool bg) {
	int i;
	r_return_val_if_fail (txt, false);
	const char *says[] = {
		"say", "termux-tts-speak", NULL
	};
	for (i = 0; says[i]; i++) {
		char *sayPath = r_file_path (says[i]);
		if (sayPath) {
			char *line = r_str_replace (strdup (txt), "'", "\"", 1);
			r_sys_cmdf ("\"%s\" '%s'%s", sayPath, line, bg? " &": "");
			free (line);
			free (sayPath);
			return true;
		}
	}
	return false;
}

Project: radare2
File: socket.c

R_API void r_socket_printf(RSocket *s, const char *fmt, ...) {
	char buf[BUFFER_SIZE];
	va_list ap;
	if (s->fd != R_INVALID_SOCKET) {
		va_start (ap, fmt);
		vsnprintf (buf, BUFFER_SIZE, fmt, ap);
		r_socket_write (s, buf, strlen (buf));
		va_end (ap);
	}
}

Project: radare2
File: sys.c

R_API bool r_sys_mkdirp(const char *dir) {
	bool ret = true;
	char slash = R_SYS_DIR[0];
	char *path = strdup (dir), *ptr = path;
	if (!path) {
		eprintf ("r_sys_mkdirp: Unable to allocate memory\n");
		return false;
	}
	if (*ptr == slash) {
		ptr++;
	}
#if __WINDOWS__
	{
		char *p = strstr (ptr, ":\\");
		if (p) {
			ptr = p + 3;
		}
	}
#endif
	for (;;) {
		// find next slash
		for (; *ptr; ptr++) {
			if (*ptr == '/' || *ptr == '\\') {
				slash = *ptr;
				break;
			}
		}
		if (!*ptr) {
			break;
		}
		*ptr = 0;
		if (!r_sys_mkdir (path) && r_sys_mkdir_failed ()) {
			eprintf ("r_sys_mkdirp: fail '%s' of '%s'\n", path, dir);
			free (path);
			return false;
		}
		*ptr = slash;
		ptr++;
	}
	if (!r_sys_mkdir (path) && r_sys_mkdir_failed ()) {
		ret = false;
	}
	free (path);
	return ret;
}

Project: radare2
File: str.c

R_API const char *r_str_str_xy(const char *s, const char *word, const char *prev, int *x, int *y) {
	r_return_val_if_fail (s && word && x && y, NULL);
	r_return_val_if_fail (word[0] != '\0' && word[0] != '\n', NULL);
	const char *src = prev ? prev + 1 : s;
	const char *d = strstr (src, word);
	if (!d) {
		return NULL;
	}
	const char *q;
	for (q = prev ? prev : s; q < d; q++) {
		if (*q == '\n') {
			(*y)++;
			*x = 0;

		} else {
			(*x)++;
		}
	}
	return d;
}

Project: radare2
File: str.c

R_API char **r_str_argv(const char *cmdline, int *_argc) {
	int argc = 0;
	int argv_len = 128; // Begin with that, argv will reallocated if necessary
	char *args; // Working buffer for writing unescaped args
	int cmdline_current = 0; // Current character index in _cmdline
	int args_current = 0; // Current character index in  args
	int arg_begin = 0; // Index of the first character of the current argument in args

	if (!cmdline) {
		return NULL;
	}

	char **argv = malloc (argv_len * sizeof (char *));
	if (!argv) {
		return NULL;
	}
	args = malloc (128 + strlen (cmdline) * sizeof (char)); // Unescaped args will be shorter, so strlen (cmdline) will be enough
	if (!args) {
		free (argv);
		return NULL;
	}
	do {
		// States for parsing args
		int escaped = 0;
		int singlequoted = 0;
		int doublequoted = 0;

		// Seek the beginning of next argument (skip whitespaces)
		while (cmdline[cmdline_current] != '\0' && IS_WHITECHAR (cmdline[cmdline_current])) {
			cmdline_current++;
		}

		if (cmdline[cmdline_current] == '\0') {
			break; // No more arguments
		}
		// Read the argument
		while (1) {
			char c = cmdline[cmdline_current];
			int end_of_current_arg = 0;
			if (escaped) {
				switch (c) {
				case '\'':
				case '"':
				case ' ':
				case '\\':
					args[args_current++] = '\\';
					args[args_current++] = c;
					break;
				case '\0':
					args[args_current++] = '\\';
					end_of_current_arg = 1;
					break;
				default:
					args[args_current++] = '\\';
					args[args_current++] = c;
				}
				escaped = 0;
			} else {
				switch (c) {
				case '\'':
					if (doublequoted) {
						args[args_current++] = c;
					} else {
						singlequoted = !singlequoted;
					}
					break;
				case '"':
					if (singlequoted) {
						args[args_current++] = c;
					} else {
						doublequoted = !doublequoted;
					}
					break;
				case '\\':
					escaped = 1;
					break;
				case ' ':
					if (singlequoted || doublequoted) {
						args[args_current++] = c;
					} else {
						end_of_current_arg = 1;
					}
					break;
				case '\0':
					end_of_current_arg = 1;
					break;
				default:
					args[args_current++] = c;
				}
			}
			if (end_of_current_arg) {
				break;
			}
			cmdline_current++;
		}
		args[args_current++] = '\0';
		argv[argc++] = strdup (&args[arg_begin]);
		if (argc >= argv_len) {
			argv_len *= 2;
			char **tmp = realloc (argv, argv_len * sizeof (char *));
			if (!tmp) {
				free (args);
				free (argv);
				return NULL;
			}
			argv = tmp;
		}
		arg_begin = args_current;
	} while (cmdline[cmdline_current++] != '\0');
	argv[argc] = NULL;
	char **tmp = realloc (argv, (argc + 1) * sizeof (char *));
	if (tmp) {
		argv = tmp;
	} else {
		free (argv);
		argv = NULL;
	}
	if (_argc) {
		*_argc = argc;
	}
	free (args);
	return argv;
}

Project: radare2
File: test_str.c

bool test_r_str_rwx_i(void) {
	const char* rwx = r_str_rwx_i (7);
	const char* rw = r_str_rwx_i (6);
	const char* rx = r_str_rwx_i (5);
	const char* invalid_mode = r_str_rwx_i (898);
	const char* invalid_mode_neg = r_str_rwx_i (-10);
	mu_assert_streq (rwx, "rwx", "rwx = 7 mode");
	mu_assert_streq (rw, "rw-", "rw = 6 mode");
	mu_assert_streq (rx, "r-x", "rx = 5 mode");
	mu_assert_streq (invalid_mode, "---", "invalid permissions mode");
	mu_assert_streq (invalid_mode_neg, "---", "invalid permissions mode (negative value)");
	mu_end;
}

Project: radare2
File: str.c

R_API char *r_str_uri_encode(const char *s) {
	char ch[4], *d, *od;
	if (!s) {
		return NULL;
	}
	od = d = malloc (1 + (strlen (s) * 4));
	if (!d) {
		return NULL;
	}
	for (; *s; s++) {
		if((*s>='0' && *s<='9')
		|| (*s>='a' && *s<='z')
		|| (*s>='A' && *s<='Z')) {
			*d++ = *s;
		} else {
			*d++ = '%';
			snprintf (ch, sizeof (ch), "%02x", 0xff & ((ut8)*s));
			*d++ = ch[0];
			*d++ = ch[1];
		}
	}
	*d = 0;
	char *trimDown = realloc (od, strlen (od) + 1); // FIT
	return trimDown? trimDown: od;
}

Project: radare2
File: sys.c

R_API char *r_sys_cmd_strf(const char *fmt, ...) {
	char *ret, cmd[4096];
	va_list ap;
	va_start (ap, fmt);
	vsnprintf (cmd, sizeof (cmd), fmt, ap);
	ret = r_sys_cmd_str (cmd, NULL, NULL);
	va_end (ap);
	return ret;
}

Project: radare2
File: str.c

R_API int *r_str_split_lines(char *str, int *count) {
	int i;
	int lines = 0;
	if (!str) {
		return NULL;
	}
	int *indexes = NULL;
	// count lines
	for (i = 0; str[i]; i++) {
		if (str[i] == '\n') {
			lines++;
		}
	}
	// allocate and set indexes
	indexes = calloc (sizeof (int), lines + 1);
	if (!indexes) {
		return NULL;
	}
	int line = 0;
	indexes[line++] = 0;
	for (i = 0; str[i]; i++) {
		if (str[i] == '\n') {
			str[i] = 0;
			indexes[line++] = i + 1;
		}
	}
	if (count) {
		*count = line;
	}
	return indexes;
}

Project: radare2
File: test_str.c

bool test_r_str_replace(void) {
	// infinite loop test
	char *str = r_str_replace (strdup ("hello world"), "hell", "ihell", 0);
	mu_assert_streq (str, "ihello world", "error, replace char multi failed");
	free (str);

	str = r_str_replace (strdup ("hello world"), "hell", "ihell", 1);
	mu_assert_streq (str, "ihello world", "error, replace char multi failed");
	free (str);

	str = r_str_replace (strdup ("hello world"), "hello", "", 1);
	mu_assert_streq (str, " world", "error, replace char multi failed");
	free (str);

	str = r_str_replace (strdup ("hello world"), "h", "hello", 0);
	mu_assert_streq (str, "helloello world", "error, replace char multi failed");
	free (str);

	str = r_str_replace (strdup ("hello horld"), "h", "hello", 1);
	mu_assert_streq (str, "helloello helloorld", "error, replace char multi failed");
	free (str);
	str = r_str_replace (strdup ("hello horld"), "h", "hello", 0);
	mu_assert_streq (str, "helloello horld", "error, replace char multi failed");
	free (str);
	mu_end;
}

Project: radare2
File: socket.c

static bool __listen_unix (RSocket *s, const char *file) {
	struct sockaddr_un unix_name;
	int sock = socket (PF_UNIX, SOCK_STREAM, 0);
	if (sock < 0) {
		return false;
	}
	// TODO: set socket options
	unix_name.sun_family = AF_UNIX;
	strncpy (unix_name.sun_path, file, sizeof (unix_name.sun_path)-1);

	/* just to make sure there is no other socket file */
	unlink (unix_name.sun_path);

	if (bind (sock, (struct sockaddr *) &unix_name, sizeof (unix_name)) < 0) {
		close (sock);
		return false;
	}
	r_sys_signal (SIGPIPE, SIG_IGN);

	/* change permissions */
	if (chmod (unix_name.sun_path, 0777) != 0) {
		close (sock);
		return false;
	}
	if (listen (sock, 1)) {
		close (sock);
		return false;
	}
	s->fd = sock;
	return true;
}

Project: radare2
File: str.c

R_API const char *r_str_sysbits(const int v) {
	switch (v) {
	case R_SYS_BITS_8: return "8";
	case R_SYS_BITS_16: return "16";
	case R_SYS_BITS_32: return "32";
	case R_SYS_BITS_64: return "64";
	case R_SYS_BITS_16 | R_SYS_BITS_32: return "16,32";
	case R_SYS_BITS_16 | R_SYS_BITS_32 | R_SYS_BITS_64: return "16,32,64";
	case R_SYS_BITS_32 | R_SYS_BITS_64: return "32,64";
	}
	return "?";
}

Project: radare2
File: test_str.c

bool test_r_str_word_count(void) {
	mu_assert_eq (r_str_word_count ("let's test\nradare2 \t libraries!"), 4,
				"words in a string");
	mu_end;
}

Project: radare2
File: str.c

R_API size_t r_str_len_utf8_ansi(const char *str) {
	int i = 0, len = 0, fullwidths = 0;
	while (str[i]) {
		char ch = str[i];
		size_t chlen = __str_ansi_length (str + i);
		if (chlen > 1) {
			i += chlen - 1;
		} else if ((ch & 0xc0) != 0x80) { // utf8
			len++;
			if (r_str_char_fullwidth (str + i, 4)) {
				fullwidths++;
			}
		}
		i++;
	}
	return len + fullwidths;
}

Project: radare2
File: str.c

R_API char* r_str_replace(char *str, const char *key, const char *val, int g) {
	if (g == 'i') {
		return r_str_replace_icase (str, key, val, g, true);
	}
	r_return_val_if_fail (str && key && val, NULL);

	int off, i, slen;
	char *newstr, *p = str;
	int klen = strlen (key);
	int vlen = strlen (val);
	if (klen == 1 && vlen < 2) {
		r_str_replace_char (str, *key, *val);
		return str;
	}
	if (klen == vlen && !strcmp (key, val)) {
		return str;
	}
	slen = strlen (str);
	char *q = str;
	for (;;) {
		p = strstr (q, key);
		if (!p) {
			break;
		}
		off = (int)(size_t)(p - str);
		if (vlen != klen) {
			int tlen = slen - (off + klen);
			slen += vlen - klen;
			if (vlen > klen) {
				newstr = realloc (str, slen + 1);
				if (!newstr) {
					eprintf ("realloc fail\n");
					R_FREE (str);
					break;
				}
				str = newstr;
			}
			p = str + off;
			memmove (p + vlen, p + klen, tlen + 1);
		}
		memcpy (p, val, vlen);
		i = off + vlen;
		q = str + i;
		if (!g) {
			break;
		}
	}
	return str;
}

Project: radare2
File: str.c

R_API int r_snprintf(char *string, int len, const char *fmt, ...) {
	va_list ap;
	va_start (ap, fmt);
	int ret = vsnprintf (string, len, fmt, ap);
	string[len - 1] = 0;
	va_end (ap);
	return ret;
}

Project: radare2
File: str.c

R_API int r_str_char_count(const char *string, char ch) {
	int i, count = 0;
	for (i = 0; string[i]; i++) {
		if (string[i] == ch) {
			count++;
		}
	}
	return count;
}

Project: radare2
File: socket.c

R_API RSocket *r_socket_new (bool is_ssl) {
	return NULL;
}

Project: radare2
File: str.c

R_API int r_str_unescape(char *buf) {
	unsigned char ch = 0, ch2 = 0;
	int err = 0;
	int i;

	for (i = 0; buf[i]; i++) {
		if (buf[i] != '\\') {
			continue;
		}
		int esc_seq_len = 2;
		switch (buf[i + 1]) {
		case 'e':
			buf[i] = 0x1b;
			break;
		case '\\':
			buf[i] = '\\';
			break;
		case 'r':
			buf[i] = 0x0d;
			break;
		case 'n':
			buf[i] = 0x0a;
			break;
		case 'a':
			buf[i] = 0x07;
			break;
		case 'b':
			buf[i] = 0x08;
			break;
		case 't':
			buf[i] = 0x09;
			break;
		case 'v':
			buf[i] = 0x0b;
			break;
		case 'f':
			buf[i] = 0x0c;
			break;
		case 'x':
			err = ch2 = ch = 0;
			if (!buf[i + 2] || !buf[i + 3]) {
				eprintf ("Unexpected end of string.\n");
				return 0;
			}
			err |= r_hex_to_byte (&ch,  buf[i + 2]);
			err |= r_hex_to_byte (&ch2, buf[i + 3]);
			if (err) {
				eprintf ("Error: Non-hexadecimal chars in input.\n");
				return 0; // -1?
			}
			buf[i] = (ch << 4) + ch2;
			esc_seq_len = 4;
			break;
		default:
			if (IS_OCTAL (buf[i + 1])) {
				int num_digits = 1;
				buf[i] = buf[i + 1] - '0';
				if (IS_OCTAL (buf[i + 2])) {
					num_digits++;
					buf[i] = (ut8)buf[i] * 8 + (buf[i + 2] - '0');
					if (IS_OCTAL (buf[i + 3])) {
						num_digits++;
						buf[i] = (ut8)buf[i] * 8 + (buf[i + 3] - '0');
					}
				}
				esc_seq_len = 1 + num_digits;
			} else {
				eprintf ("Error: Unknown escape sequence.\n");
				return 0; // -1?
			}
		}
		memmove (buf + i + 1, buf + i + esc_seq_len, strlen (buf + i + esc_seq_len) + 1);
	}
	return i;
}

Project: radare2
File: str.c

static size_t __str_ansi_length(char const *str) {
	size_t i = 1;
	if (str[0] == 0x1b) {
		if (str[1] == '[') {
			i++;
			while (str[i] && str[i] != 'J' && str[i] != 'm' && str[i] != 'H' && str[i] != 'K') {
				i++;
			}
		} else if (str[1] == '#') {
			while (str[i] && str[i] != 'q') {
				i++;
			}
		}
		if (str[i]) {
			i++;
		}
	}
	return i;
}

Project: radare2
File: sys.c

static int checkcmd(const char *c) {
	char oc = 0;
	for (;*c;c++) {
		if (oc == '%') {
			if (*c != 'd' && *c != '%') {
				return 0;
			}
		}
		oc = *c;
	}
	return 1;
}

Project: radare2
File: str.c

R_API char *r_str_prefix_all(const char *s, const char *pfx) {
	const char *os = s;
	char *p;
	int newlines = 1;
	int len = 0;
	int pfx_len = 0;

	if (!s) {
		return strdup (pfx);
	}
	if (!pfx) {
		return strdup (s);
	}
	len = strlen (s);
	pfx_len = strlen (pfx);
	for (os = s; *os; os++)  {
		if (*os == '\n') {
			newlines++;
		}
	}
	char *o = malloc (len + (pfx_len * newlines) + 1);
	if (!o) {
		return NULL;
	}
	memcpy (o, pfx, pfx_len);
	for (p = o + pfx_len; *s; s++) {
		*p++ = *s;
		if (*s == '\n' && s[1]) {
			memcpy (p, pfx, pfx_len);
			p += pfx_len;
		}
	}
	*p = 0;
	return o;
}

Project: radare2
File: str.c

R_API int r_str_bits64(char* strout, ut64 in) {
	int i, bit, count = 0;
	count = 0;
	for (i = (sizeof (in) * 8) - 1; i >= 0; i--) {
		bit = in >> i;
		if (bit & 1) {
			strout[count] = '1';
		} else {
			strout[count] = '0';
		}
		count++;
	}
	strout[count] = '\0';
	/* trim by 8 bits */
	trimbits (strout);
	return count;
}

Project: radare2
File: sys.c

R_API int r_sys_getpid() {
#if __UNIX__
	return getpid ();
#elif __WINDOWS__
	return GetCurrentProcessId();
#else
#warning r_sys_getpid not implemented for this platform
	return -1;
#endif
}

Project: radare2
File: sys.c

R_API const char *r_sys_prefix(const char *pfx) {
	static char *prefix = NULL;
	if (!prefix) {
#if __WINDOWS__
		prefix = r_sys_get_src_dir_w32 ();
		if (!prefix) {
			prefix = strdup (R2_PREFIX);
		}
#else
		prefix = strdup (R2_PREFIX);
#endif
	}
	if (pfx) {
		free (prefix);
		prefix = strdup (pfx);
	}
	return prefix;
}

Project: radare2
File: socket.c

R_API bool r_socket_listen (RSocket *s, const char *port, const char *certfile) {
	return false;
}

Project: radare2
File: socket.c

R_API bool r_socket_is_connected (RSocket *s) {
	return false;
}

Project: radare2
File: sys.c

R_API void r_sys_exit(int status, bool nocleanup) {
	if (nocleanup) {
		_exit (status);
	} else {
		exit (status);
	}
}

Project: radare2
File: disk.c

static wchar_t *r_utf8_to_utf16_l (const char *cstring, int len) {
	if (!cstring || !len || len < -1) {
		return NULL;
	}
	wchar_t *rutf16 = NULL;
	int wcsize;

	if ((wcsize = MultiByteToWideChar (CP_UTF8, 0, cstring, len, NULL, 0))) {
		wcsize += 1;
		if ((rutf16 = (wchar_t *) calloc (wcsize, sizeof (wchar_t)))) {
			MultiByteToWideChar (CP_UTF8, 0, cstring, len, rutf16, wcsize);
			if (len != -1) {
				rutf16[wcsize - 1] = L'\0';
			}
		}
	}
	return rutf16;
}

Project: radare2
File: sys.c

R_API void r_sys_perror_str(const char *fun) {
#if __UNIX__
#pragma push_macro("perror")
#undef perror
	perror (fun);
#pragma pop_macro("perror")
#elif __WINDOWS__
	LPTSTR lpMsgBuf;
	DWORD dw = GetLastError();

	if (FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER |
			FORMAT_MESSAGE_FROM_SYSTEM |
			FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL,
			dw,
			MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
			(LPTSTR)&lpMsgBuf,
			0, NULL )) {
		char *err = r_sys_conv_win_to_utf8 (lpMsgBuf);
		if (err) {
			eprintf ("%s: %s\n", fun, err);
			free (err);
		}
		LocalFree (lpMsgBuf);
	} else {
		eprintf ("%s\n", fun);
	}
#endif
}

Project: radare2
File: str.c

R_API size_t r_str_ansi_nlen(const char *str, size_t slen) {
	size_t i = 0, len = 0;
	if (slen > 0) {
		while (str[i] && i < slen) {
			size_t chlen = __str_ansi_length (str + i);
			if (chlen == 1) {
				len ++;
			}
			i += chlen;
		}
		return len > 0 ? len: 1;
	}
	while (str[i]) {
		size_t chlen = __str_ansi_length (str + i);
		if (chlen == 1) {
			len ++;
		}
		i += chlen;
	}
	return len > 0 ? len: 1;
}

Project: radare2
File: str.c

R_API char *r_str_dup(char *ptr, const char *string) {
	free (ptr);
	return r_str_new (string);
}

Project: radare2
File: str.c

R_API char *r_str_home(const char *str) {
	char *dst, *home = r_sys_getenv (R_SYS_HOME);
	size_t length;
	if (!home) {
		home = r_file_tmpdir ();
		if (!home) {
			return NULL;
		}
	}
	length = strlen (home) + 1;
	if (str) {
		length += strlen (R_SYS_DIR) + strlen (str);
	}
	dst = (char *)malloc (length);
	if (!dst) {
		goto fail;
	}
	int home_len = strlen (home);
	memcpy (dst, home, home_len + 1);
	if (str) {
		dst[home_len] = R_SYS_DIR[0];
		strcpy (dst + home_len + 1, str);
	}
fail:
	free (home);
	return dst;
}

Project: radare2
File: str.c

R_API void r_str_truncate_cmd(char *string) {
	ut32 pos = 0;
	if (string && *string) {
		ut32 sz = strlen (string);
		for (pos = 0; pos < sz; pos++) {
			switch (string[pos]) {
			case '!':
			case ':':
			case ';':
			case '@':
			case '~':
			case '(':
			case '[':
			case '{':
			case '?':
				string[pos] = '\0';
				return;
			}
		}
	}
}

Project: radare2
File: test_str.c

bool test_r_str_len_utf8_ansi(void) {
	int len;

	len = r_str_len_utf8_ansi ("radare2");
	mu_assert_eq (len, 7, "len(ascii only)");

	len = r_str_len_utf8_ansi ("r\x1b[38;2;208;80;0madare2");
	mu_assert_eq (len, 7, "len(ascii + ansi ending with m)");

	len = r_str_len_utf8_ansi ("r\x1b[0Jadare2");
	mu_assert_eq (len, 7, "len(ascii + ansi ending with J)");

	len = r_str_len_utf8_ansi ("r\x1b[42;42Hadare2");
	mu_assert_eq (len, 7, "len(ascii + ansi ending with H)");

	len = r_str_len_utf8_ansi ("r\xc3\xa4""dare2");
	mu_assert_eq (len, 7, "len(ascii + 2 byte utf-8 counted as 1 char)");

	len = r_str_len_utf8_ansi ("radar\xe2\x82\xac""2");
	mu_assert_eq (len, 7, "len(ascii + 3 byte utf-8 counted as 1 char)");

	len = r_str_len_utf8_ansi ("radar\xf0\x9d\x84\x9e""2");
	mu_assert_eq (len, 7, "len(ascii + 4 byte utf-8 counted as 1 char)");

	mu_end;
}

Project: radare2
File: str.c

R_API char *r_str_utf16_decode(const ut8 *s, int len) {
	int i = 0;
	int j = 0;
	char *result = NULL;
	int count_unicode = 0;
	int count_ascii = 0;
	int lenresult = 0;
	if (!s) {
		return NULL;
	}
	for (i = 0; i < len && (s[i] || s[i+1]); i += 2) {
		if (!s[i+1] && 0x20 <= s[i] && s[i] <= 0x7E) {
			++count_ascii;
		} else {
			++count_unicode;
		}
	}
	lenresult = 1 + count_ascii + count_unicode * 6; // len("\\uXXXX") = 6
	if (!(result = calloc (1 + count_ascii + count_unicode * 6, 1))) {
		return NULL;
	}
	for (i = 0; i < len && j < lenresult && (s[i] || s[i+1]); i += 2) {
		if (!s[i+1] && IS_PRINTABLE(s[i])) {
			result[j++] = s[i];
		} else {
			j += snprintf (&result[j], lenresult - j, "\\u%.2"HHXFMT"%.2"HHXFMT"", s[i], s[i+1]);
		}
	}
	return result;
}

Project: radare2
File: sys.c

R_API int r_sys_sigaction(int *sig, void (*handler) (int)) {
	int ret, i;

	if (!sig) {
		return -EINVAL;
	}

	for (i = 0; sig[i] != 0; i++) {
		ret = signal (sig[i], handler);
		if (ret == SIG_ERR) {
			eprintf ("Failed to set signal handler for signal '%d': %s\n", sig[i], strerror(errno));
			return -1;
		}
	}
	return 0;
}

Project: radare2
File: sys.c

R_API bool r_sys_getenv_asbool(const char *key) {
	char *env = r_sys_getenv (key);
	const bool res = (env && *env == '1');
	free (env);
	return res;
}

Project: radare2
File: str.c

R_API char *r_str_ichr(char *str, char chr) {
	while (*str == chr) {
		str++;
	}
	return str;
}

Project: radare2
File: sys.c

R_API char *r_sys_whoami (char *buf) {
	char _buf[32];
	int pid = getpid ();
	int hasbuf = (buf)? 1: 0;
	if (!hasbuf) {
		buf = _buf;
	}
	sprintf (buf, "pid%d", pid);
	return hasbuf? buf: strdup (buf);
}

Project: radare2
File: str.c

R_API char *r_str_word_get0set(char *stra, int stralen, int idx, const char *newstr, int *newlen) {
	char *p = NULL;
	char *out;
	int alen, blen, nlen;
	if (!stra && !newstr) {
		return NULL;
	}
	if (stra) {
		p = (char *)r_str_word_get0 (stra, idx);
	}
	if (!p) {
		int nslen = strlen (newstr);
		out = malloc (nslen + 1);
		if (!out) {
			return NULL;
		}
		strcpy (out, newstr);
		out[nslen] = 0;
		if (newlen) {
			*newlen = nslen;
		}
		return out;
	}
	alen = (size_t)(p - stra);
	blen = stralen - ((alen + strlen (p)) + 1);
	if (blen < 0) {
		blen = 0;
	}
	nlen = alen + blen + strlen (newstr);
	out = malloc (nlen + 2);
	if (!out) {
		return NULL;
	}
	if (alen > 0) {
		memcpy (out, stra, alen);
	}
	memcpy (out + alen, newstr, strlen (newstr) + 1);
	if (blen > 0) {
		memcpy (out + alen + strlen (newstr) + 1, p + strlen (p) + 1, blen + 1);
	}
	out[nlen + 1] = 0;
	if (newlen) {
		*newlen = nlen + ((blen == 0)? 1 : 0);
	}
	return out;
}

Project: radare2
File: str.c

R_API char *r_str_append(char *ptr, const char *string) {
	if (string && !ptr) {
		return strdup (string);
	}
	if (!string) {
		return ptr;
	}
	int plen = strlen (ptr);
	int slen = strlen (string);
	char *newptr = realloc (ptr, slen + plen + 1);
	if (!newptr) {
		free (ptr);
		return NULL;
	}
	ptr = newptr;
	memcpy (ptr + plen, string, slen + 1);
	return ptr;
}

Project: radare2
File: socket.c

R_API bool r_socket_connect(RSocket *s, const char *host, const char *port, int proto, unsigned int timeout) {
	r_return_val_if_fail (s, false);
#if __WINDOWS__
#define gai_strerror gai_strerrorA
	struct sockaddr_in sa;
	WSADATA wsadata;

	if (WSAStartup (MAKEWORD (1, 1), &wsadata) == SOCKET_ERROR) {
		eprintf ("Error creating socket.");
		return false;
	}
#endif
	int ret;
	struct addrinfo hints = { 0 };
	struct addrinfo *res, *rp;
	if (!proto) {
		proto = R_SOCKET_PROTO_TCP;
	}
#if __UNIX__
	r_sys_signal (SIGPIPE, SIG_IGN);
#endif
	if (proto == R_SOCKET_PROTO_UNIX) {
#if __UNIX__
		if (!__connect_unix (s, host)) {
			return false;
		}
#endif
	} else {
		hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
		hints.ai_protocol = proto;
		int gai = getaddrinfo (host, port, &hints, &res);
		if (gai != 0) {
			eprintf ("r_socket_connect: Error in getaddrinfo: %s (%s:%s)\n",
				gai_strerror (gai), host, port);
			return false;
		}
		for (rp = res; rp != NULL; rp = rp->ai_next) {
			int flag = 1;

			s->fd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
			if (s->fd == -1) {
				perror ("socket");
				continue;
			}
			ret = setsockopt (s->fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof (flag));
			if (ret < 0) {
				perror ("setsockopt");
				close (s->fd);
				s->fd = -1;
				continue;
			}

			r_socket_block_time (s, 0, 0, 0);
			ret = connect (s->fd, rp->ai_addr, rp->ai_addrlen);

			if (ret == 0) {
				freeaddrinfo (res);
				return true;
			}
			if (errno == EINPROGRESS) {
				struct timeval tv = {timeout, 0};
				fd_set wfds;
				FD_ZERO (&wfds);
				FD_SET (s->fd, &wfds);

				if ((ret = select (s->fd + 1, NULL, &wfds, NULL, &tv)) != -1) {
					if (r_socket_is_connected (s)) {
						freeaddrinfo (res);
						goto success;
					}
				} else {
					perror ("connect");
				}
			}
			r_socket_close (s);
		}
		freeaddrinfo (res);
		if (!rp) {
			eprintf ("Could not resolve address '%s' or failed to connect\n", host);
			return false;
		}
	}
success:
#if HAVE_LIB_SSL
	if (s->is_ssl) {
		s->ctx = SSL_CTX_new (SSLv23_client_method ());
		if (!s->ctx) {
			r_socket_close (s);
			return false;
		}
		s->sfd = SSL_new (s->ctx);
		SSL_set_fd (s->sfd, s->fd);
		int ret = SSL_connect (s->sfd);
		if (ret != 1) {
			int error = SSL_get_error (s->sfd, ret);
			int tries = 10;
			while (tries && ret && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)) {
				struct timeval tv = {1, 0};
				fd_set rfds, wfds;
				FD_ZERO (&rfds);
				FD_ZERO (&wfds);
				if (error == SSL_ERROR_WANT_READ) {
					FD_SET (s->fd, &rfds);
				} else {
					FD_SET (s->fd, &wfds);
				}
				if ((ret = select (s->fd + 1, &rfds, &wfds, NULL, &tv)) < 1) {
					r_socket_close (s);
					return false;
				}
				ret = SSL_connect (s->sfd);
				if (ret == 1) {
					return true;
				}
				error = SSL_get_error (s->sfd, ret);
				tries--;
			}
			r_socket_close (s);
			return false;
		}
	}
#endif
	return true;
}

Project: radare2
File: str.c

R_API char *r_str_ndup(const char *ptr, int len) {
	if (len < 0) {
		return NULL;
	}
	char *out = malloc (len + 1);
	if (!out) {
		return NULL;
	}
	strncpy (out, ptr, len);
	out[len] = 0;
	return out;
}

Project: radare2
File: str.c

R_API bool r_str_is_false(const char *s) {
	return !r_str_casecmp ("no", s)
		|| !r_str_casecmp ("off", s)
		|| !r_str_casecmp ("false", s)
		|| !r_str_casecmp ("0", s)
		|| !*s;
}

Project: radare2
File: str.c

R_API const char *r_str_pad(const char ch, int sz) {
	static char pad[1024];
	if (sz < 0) {
		sz = 0;
	}
	memset (pad, ch, R_MIN (sz, sizeof (pad)));
	if (sz < sizeof (pad)) {
		pad[sz] = 0;
	}
	pad[sizeof(pad) - 1] = 0;
	return pad;
}

Project: radare2
File: sys.c

R_API RList *r_sys_dir(const char *path) {
	RList *list = NULL;
#if __WINDOWS__
	WIN32_FIND_DATAW entry;
	char *cfname;
	HANDLE fh = r_sandbox_opendir (path, &entry);
	if (fh == INVALID_HANDLE_VALUE) {
		//IFDGB eprintf ("Cannot open directory %ls\n", wcpath);
		return list;
	}
	list = r_list_newf (free);
	if (list) {
		do {
			if ((cfname = r_utf16_to_utf8 (entry.cFileName))) {
				r_list_append (list, strdup (cfname));
				free (cfname);
			}
		} while (FindNextFileW (fh, &entry));
	}
	FindClose (fh);
#else
	struct dirent *entry;
	DIR *dir = r_sandbox_opendir (path);
	if (dir) {
		list = r_list_new ();
		if (list) {
			list->free = free;
			while ((entry = readdir (dir))) {
				r_list_append (list, strdup (entry->d_name));
			}
		}
		closedir (dir);
	}
#endif
	return list;
}

Project: radare2
File: socket_http.c

static char *socket_http_get_recursive(const char *url, int *code, int *rlen, ut32 redirections) {
	if (code) {
		*code = 0;
	}
	if (rlen) {
		*rlen = 0;
	}
	char *curl_env = r_sys_getenv ("R2_CURL");
	if (!R_STR_ISEMPTY (curl_env) && atoi (curl_env)) {
		int len;
		char *escaped_url = r_str_escape_sh (url);
		char *command = r_str_newf ("curl -sfL -o - \"%s\"", escaped_url);
		char *res = r_sys_cmd_str (command, NULL, &len);
		free (escaped_url);
		free (command);
		free (curl_env);
		if (!res) {
			return NULL;
		}
		if (res) {
			if (code) {
				*code = 200;
			}
			if (rlen) {
				*rlen = len;
			}
		}
		return res;
	}
	free (curl_env);
#if __WINDOWS__
	return http_get_w32 (url, code, rlen);
#else
	RSocket *s;
	int ssl = r_str_startswith (url, "https://");
#if !HAVE_LIB_SSL
	if (ssl) {
		eprintf ("Tried to get '%s', but SSL support is disabled, set R2_CURL=1 to use curl\n", url);
		return NULL;
	}
#endif
	char *response, *host, *path, *port = "80";
	char *uri = strdup (url);
	if (!uri) {
		return NULL;
	}
	host = strstr (uri, "://");
	if (!host) {
		free (uri);
		eprintf ("r_socket_http_get: Invalid URI");
		return NULL;
	}
	host += 3;
	port = strchr (host, ':');
	if (!port) {
		port = ssl? "443": "80";
		path = host;
	} else {
		*port++ = 0;
		path = port;
	}
	path = strchr (path, '/');
	if (!path) {
		path = "";
	} else {
		*path++ = 0;
	}
	s = r_socket_new (ssl);
	if (!s) {
		eprintf ("r_socket_http_get: Cannot create socket\n");
		free (uri);
		return NULL;
	}
	if (r_socket_connect_tcp (s, host, port, 0)) {
		r_socket_printf (s,
				"GET /%s HTTP/1.1\r\n"
				"User-Agent: radare2 "R2_VERSION"\r\n"
				"Accept: */*\r\n"
				"Host: %s:%s\r\n"
				"\r\n", path, host, port);
		response = socket_http_answer (s, code, rlen, redirections);
	} else {
		eprintf ("Cannot connect to %s:%s\n", host, port);
		response = NULL;
	}
	free (uri);
	r_socket_free (s);
	return response;
#endif
}

Project: radare2
File: socket.c

R_API void r_socket_printf(RSocket *s, const char *fmt, ...) {
	/* nothing here */
}

Project: radare2
File: test_str.c

bool test_r_str_format_msvc_argv() {
	// Examples from http://daviddeley.com/autohotkey/parameters/parameters.htm#WINCRULES
	const char *a = "CallMePancake";
	char *str = r_str_format_msvc_argv (1, &a);
	mu_assert_streq (str, "CallMePancake", "no escaping");
	free (str);

	a = "Call Me Pancake";
	str = r_str_format_msvc_argv (1, &a);
	mu_assert_streq (str, "\"Call Me Pancake\"", "just quoting");
	free (str);

	a = "CallMe\"Pancake";
	str = r_str_format_msvc_argv (1, &a);
	mu_assert_streq (str, "CallMe\\\"Pancake", "just escaping");
	free (str);

	a = "CallMePancake\\";
	str = r_str_format_msvc_argv (1, &a);
	mu_assert_streq (str, "CallMePancake\\", "no escaping of backslashes");
	free (str);

	a = "Call Me Pancake\\";
	str = r_str_format_msvc_argv (1, &a);
	mu_assert_streq (str, "\"Call Me Pancake\\\\\"", "escaping of backslashes before closing quote");
	free (str);

	a = "CallMe\\\"Pancake";
	str = r_str_format_msvc_argv (1, &a);
	mu_assert_streq (str, "CallMe\\\\\\\"Pancake", "escaping of backslashes before literal quote");
	free (str);

	a = "Call Me\\\"Pancake";
	str = r_str_format_msvc_argv (1, &a);
	mu_assert_streq (str, "\"Call Me\\\\\\\"Pancake\"", "escaping of backslashes before literal quote in quote");
	free (str);

	const char *args[] = { "rm", "-rf", "\\"};
	str = r_str_format_msvc_argv (3, args);
	mu_assert_streq (str, "rm -rf \\", "multiple args");
	free (str);

	mu_end;
}

Project: radare2
File: str.c

R_API char *r_str_escape_utf16le(const char *buf, int buf_size, bool show_asciidot, bool esc_bslash) {
	return r_str_escape_utf (buf, buf_size, R_STRING_ENC_UTF16LE, show_asciidot, esc_bslash, false);
}

Project: radare2
File: str.c

R_API bool r_str_startswith(const char *str, const char *needle) {
	r_return_val_if_fail (str && needle, false);
	if (str == needle) {
		return true;
	}
	return !strncmp (str, needle, strlen (needle));
}

Project: radare2
File: str.c

R_API size_t r_wstr_clen(const char *s) {
	size_t len = 0;
	if (!*s++) {
		return 0;
	}
	while (*s++ || *s++) {
		len++;
	}
	return len + 1;
}

Project: radare2
File: socket.c

R_API int r_socket_read(RSocket *s, unsigned char *buf, int len) {
	if (!s) {
		return -1;
	}
#if HAVE_LIB_SSL
	if (s->is_ssl) {
		if (s->bio) {
			return BIO_read (s->bio, buf, len);
		}
		return SSL_read (s->sfd, buf, len);
	}
#endif
	// int r = read (s->fd, buf, len);
	int r = recv (s->fd, buf, len, 0);
	D { eprintf ("READ "); int i; for (i = 0; i<len; i++) { eprintf ("%02x ", buf[i]); } eprintf ("\n"); }
	return r;
}

Project: radare2
File: str.c

R_API char *r_str_version(const char *program) {
	char *s = r_str_newf ("%s "R2_VERSION" %d @ "
			R_SYS_OS"-"
			R_SYS_ARCH"-%d git.%s\n",
			program, R2_VERSION_COMMIT,
			(R_SYS_BITS & 8)? 64: 32,
			*R2_GITTAP ? R2_GITTAP: "");
	if (*R2_GITTIP) {
		s = r_str_appendf (s, "commit: "R2_GITTIP" build: "R2_BIRTH);
	}
	return s;
}

Project: radare2
File: sys.c

R_API int r_sys_run_rop(const ut8 *buf, int len) {
#if USE_FORK
	int st;
#endif
	// TODO: define R_SYS_ALIGN_FORWARD in r_util.h
	ut8 *bufptr = malloc (len);
	if (!bufptr) {
		eprintf ("r_sys_run_rop: Cannot allocate buffer\n");
		return false;
	}

	if (!buf) {
		eprintf ("r_sys_run_rop: Cannot execute empty rop chain\n");
		free (bufptr);
		return false;
	}
	memcpy (bufptr, buf, len);
#if USE_FORK
#if __UNIX__
	pid_t pid = r_sys_fork ();
#else
	pid = -1;
#endif
	if (pid < 0) {
		R_SYS_ASM_START_ROP ();
	} else {
		R_SYS_ASM_START_ROP ();
		exit (0);
                return 0;
	}
	st = 0;
	if (waitpid (pid, &st, 0) == -1) {
            eprintf ("r_sys_run_rop: waitpid failed\n");
            free (bufptr);
            return -1;
        }
	if (WIFSIGNALED (st)) {
		int num = WTERMSIG (st);
		eprintf ("Got signal %d\n", num);
		ret = num;
	} else {
		ret = WEXITSTATUS (st);
	}
#else
	R_SYS_ASM_START_ROP ();
#endif
	free (bufptr);
	return 0;
}

Project: radare2
File: pdb_downloader.c

static bool download_and_write(SPDBDownloaderOpt *opt, const char *file) {
	char *dir = r_str_newf ("%s%s%s%s%s",
		opt->symbol_store_path, R_SYS_DIR,
		opt->dbg_file, R_SYS_DIR,
		opt->guid);
	if (!r_sys_mkdirp (dir)) {
		free (dir);
		return false;
	}
	char *url = r_str_newf ("%s/%s/%s/%s", opt->symbol_server, opt->dbg_file, opt->guid, file);
	int len;
	char *file_buf = r_socket_http_get (url, NULL, &len);
	free (url);
	if (!len || R_STR_ISEMPTY (file_buf)) {
		free (dir);
		free (file_buf);
		return false;
	}
	char *path = r_str_newf ("%s%s%s", dir, R_SYS_DIR, opt->dbg_file);
	FILE *f = fopen (path, "wb");
	if (f) {
		fwrite (file_buf, sizeof (char), (size_t)len, f);
		fclose (f);
	}
	free (dir);
	free (path);
	free (file_buf);
	return true;
}

Project: radare2
File: test_str.c

bool test_r_str_replace_char(void) {
	char* str = strdup ("hello world");
	(void) r_str_replace_char (str, 'l', 'x');
	mu_assert_streq (str, "hexxo worxd", "error, replace char multi failed");
	free (str);
	mu_end;
}

Project: radare2
File: socket.c

R_API ut8* r_socket_slurp(RSocket *s, int *len) {
	int blockSize = 4096;
	ut8 *ptr, *buf = malloc (blockSize);
	if (!buf) {
		return NULL;
	}
	int copied = 0;
	if (len) {
		*len = 0;
	}
	for (;;) {
		int rc = r_socket_read (s, buf + copied, blockSize);
		if (rc > 0) {
			copied += rc;
		}
		ptr = realloc (buf, copied + blockSize);
		if (!ptr) {
			break;
		}
		buf = ptr;
		if (rc < 1) {
			break;
		}
	}
	if (copied == 0) {
		R_FREE (buf);
	}
	if (len) {
		*len = copied;
	}
	return buf;
}

Project: radare2
File: sys.c

R_API int r_sys_thp_mode(void) {
#if __linux__
	const char *thp = "/sys/kernel/mm/transparent_hugepage/enabled";
	int ret = 0;
	char *val = r_file_slurp (thp, NULL);
	if (val) {
		if (strstr (val, "[madvise]")) {
			ret = 1;
		} else if (strstr (val, "[always]")) {
			ret = 2;
		}
		free (val);
	}

	return ret;
#else
  return 0;
#endif
}

Project: radare2
File: socket.c

R_API int r_socket_port_by_name(const char *name) {
	struct servent *p = getservbyname (name, "tcp");
	return (p && p->s_port) ? ntohs (p->s_port) : r_num_get (NULL, name);
}

Project: radare2
File: str.c

R_API char* r_str_replace_thunked(char *str, char *clean, int *thunk, int clen,
				  const char *key, const char *val, int g) {
	int i, klen, vlen, slen, delta = 0, bias;
	char *newstr, *scnd, *p = clean, *str_p;

	if (!str || !key || !val || !clean || !thunk) {
		return NULL;
	}
	klen = strlen (key);
	vlen = strlen (val);
	if (klen == vlen && !strcmp (key, val)) {
		return str;
	}
	slen = strlen (str) + 1;

	for (i = 0; i < clen; ) {
		p = (char *)r_mem_mem (
			(const ut8*)clean + i, clen - i,
			(const ut8*)key, klen);
		if (!p) {
			break;
		}
		i = (int)(size_t)(p - clean);
		/* as the original string changes size during replacement
		 * we need delta to keep track of it*/
		str_p = str + thunk[i] + delta;

		int newo = thunk[i + klen] - thunk[i];
		r_str_ansi_filter (str_p, NULL, NULL, newo);
		scnd = strdup (str_p + newo);
		bias = vlen - newo;

		slen += bias;
		// HACK: this 32 avoids overwrites wtf
		newstr = realloc (str, slen + klen);
		if (!newstr) {
			eprintf ("realloc fail\n");
			R_FREE (str);
			free (scnd);
			break;
		}
		str = newstr;
		str_p = str + thunk[i] + delta;
		memcpy (str_p, val, vlen);
		memcpy (str_p + vlen, scnd, strlen (scnd) + 1);
		i += klen;
		delta += bias;
		free (scnd);
		if (!g) {
			break;
		}
	}
	return str;
}

Project: radare2
File: str.c

R_API size_t r_str_len_utf8char(const char *s, int left) {
	size_t i = 1;
	while (s[i] && (!left || i<left)) {
		if ((s[i] & 0xc0) != 0x80) {
			i++;
		} else {
			break;
		}
	}
	return i;
}

Project: radare2
File: str.c

R_API bool r_str_is_printable(const char *str) {
	while (*str) {
		int ulen = r_utf8_decode ((const ut8*)str, strlen (str), NULL);
		if (ulen > 1) {
			str += ulen;
			continue;
		}
		if (!IS_PRINTABLE (*str)) {
			return false;
		}
		str++;
	}
	return true;
}

Project: radare2
File: str.c

R_API RList *r_str_split_duplist(const char *_str, const char *c) {
	r_return_val_if_fail (_str && c, NULL);
	RList *lst = r_list_newf (free);
	char *str = strdup (_str);
	char *aux = str;
	size_t clen = strlen (c);
	while (aux) {
		char *next = strstr (aux, c);
		if (next) {
			*next = '\0';
			next += clen;
		}
		r_str_trim (aux);
		r_list_append (lst, strdup (aux));
		aux = next;
	}
	free (str);
	return lst;
}

Project: radare2
File: str.c

R_API char *r_str_escape_utf8(const char *buf, bool show_asciidot, bool esc_bslash) {
	return r_str_escape_utf (buf, -1, R_STRING_ENC_UTF8, show_asciidot, esc_bslash, false);
}

Project: radare2
File: str.c

R_API ut8 r_str_contains_macro(const char *input_value) {
	char *has_tilde = input_value ? HASCH('~') : NULL,
		 *has_bang = input_value ? HASCH('!') : NULL,
		 *has_brace = input_value ? CAST(HASCH('[') || HASCH(']')) : NULL,
		 *has_paren = input_value ? CAST(HASCH('(') || HASCH(')')) : NULL,
		 *has_cbrace = input_value ? CAST(HASCH('{') || HASCH('}')) : NULL,
		 *has_qmark = input_value ? HASCH('?') : NULL,
		 *has_colon = input_value ? HASCH(':') : NULL,
		 *has_at = input_value ? strchr (input_value, '@') : NULL;

	return has_tilde || has_bang || has_brace || has_cbrace || has_qmark \
		|| has_paren || has_colon || has_at;
}

Project: radare2
File: str.c

static int strncpy_with_color_codes(char *s1, char *s2, int n) {
	int i = 0, j = 0;
	int count = 0;
	while (s2[j] && count < n) {
		// detect (consecutive) color codes
		while (s2[j] == 0x1b) {
			// copy till 'm'
			while (s2[j] && s2[j] != 'm') {
				s1[i++] = s2[j++];
			}
			// copy 'm'
			if (s2[j]) {
				s1[i++] = s2[j++];
			}
		}
		if (s2[j]) {
			s1[i++] = s2[j++];
			count++;
		}
	}
	return i;
}

Project: radare2
File: str.c

R_API char *r_str_escape_dot(const char *buf) {
	return r_str_escape_ (buf, true, true, true, false, true);
}

Project: radare2
File: socket_http.c

R_API char *r_socket_http_get(const char *url, int *code, int *rlen) {
	return socket_http_get_recursive (url, code, rlen, SOCKET_HTTP_MAX_REDIRECTS);
}

Project: radare2
File: str.c

R_API const char *r_str_casestr(const char *a, const char *b) {
	// That's a GNUism that works in many places.. but we don't want it
	// return strcasestr (a, b);
	size_t hay_len = strlen (a);
	size_t needle_len = strlen (b);
	if (!hay_len || !needle_len) {
		return NULL;
	}
	while (hay_len >= needle_len) {
		if (!r_str_ncasecmp (a, b, needle_len)) {
			return (const char *) a;
		}
		a++;
		hay_len--;
	}
	return NULL;
}

Project: radare2
File: str.c

R_API bool r_str_cmp_list(const char *list, const char *item, char sep) {
	if (!list || !item) {
		return false;
	}
	int i = 0, j = 0;
	for (; list[i] && list[i] != sep; i++, j++) {
		if (item[j] != list[i]) {
			while (list[i] && list[i] != sep) {
				i++;
			}
			if (!list[i]) {
				return false;
			}
			j = -1;
			continue;
		}
	}
	return true;
}

Project: radare2
File: str.c

R_API bool r_str_is_ascii(const char *str) {
	const ut8 *ptr;
	for (ptr = (const ut8 *)str; *ptr; ptr++) {
		if (*ptr > 0x7f) {
			return false;
		}
	}
	return true;
}

Project: radare2
File: socket.c

R_API bool r_socket_spawn(RSocket *s, const char *cmd, unsigned int timeout) {
	// XXX TODO: dont use sockets, we can achieve the same with pipes
	const int port = 2000 + r_num_rand (2000);
	int childPid = r_sys_fork ();
	if (childPid == 0) {
		char *a = r_str_replace (strdup (cmd), "\\", "\\\\", true);
		int res = r_sys_cmdf ("rarun2 system=\"%s\" listen=%d", a, port);
		free (a);
#if 0
		// TODO: use the api
		char *profile = r_str_newf (
				"system=%s\n"
				"listen=%d\n", cmd, port);
		RRunProfile *rp = r_run_new (profile);
		r_run_start (rp);
		r_run_free (rp);
		free (profile);
#endif
		if (res != 0) {
			eprintf ("r_socket_spawn: rarun2 failed\n");
			exit (1);
		}
		eprintf ("r_socket_spawn: %s is dead\n", cmd);
		exit (0);
	}
	r_sys_sleep (1);
	r_sys_usleep (timeout);

	char aport[32];
	sprintf (aport, "%d", port);
	// redirect stdin/stdout/stderr
	bool sock = r_socket_connect (s, "127.0.0.1", aport, R_SOCKET_PROTO_TCP, 2000);
	if (!sock) {
		return false;
	}
#if __UNIX__
	r_sys_sleep (4);
	r_sys_usleep (timeout);

	int status = 0;
	int ret = waitpid (childPid, &status, WNOHANG);
	if (ret != 0) {
		r_socket_close (s);
		return false;
	}
#endif
	return true;
}

Project: radare2
File: pdb_downloader.c

static bool checkExtract() {
#if __WINDOWS__
	if (r_sys_cmd ("expand -? >nul") != 0) {
		return false;
	}
#else
	if (r_sys_cmd ("cabextract -v > /dev/null") != 0) {
		return false;
	}
#endif
	return true;
}

Project: radare2
File: sys.c

R_API void r_sys_backtrace(void) {
#ifdef HAVE_BACKTRACE
	void *array[10];
	size_t size = backtrace (array, 10);
	eprintf ("Backtrace %zd stack frames.\n", size);
	backtrace_symbols_fd (array, size, 2);
#elif __APPLE__
	void **fp = (void **) __builtin_frame_address (0);
	void *saved_pc = __builtin_return_address (0);
	void *saved_fp = __builtin_frame_address (1);
	int depth = 0;

	printf ("[%d] pc == %p fp == %p\n", depth++, saved_pc, saved_fp);
	fp = saved_fp;
	while (fp) {
		saved_fp = *fp;
		fp = saved_fp;
		if (!*fp) {
			break;
		}
		saved_pc = *(fp + 2);
		printf ("[%d] pc == %p fp == %p\n", depth++, saved_pc, saved_fp);
	}
#else
#ifdef _MSC_VER
#pragma message ("TODO: r_sys_bt : unimplemented")
#else
#warning TODO: r_sys_bt : unimplemented
#endif
#endif
}

Project: radare2
File: str.c

R_API char* r_str_wc_to_mb(const wchar_t *buf) {
	if (!buf) {
		return NULL;
	}
	return r_str_wc_to_mb_l (buf, wcslen (buf));
}

Project: radare2
File: str.c

R_API void r_str_argv_free(char **argv) {
	int argc = 0;
	if (!argv) {
		return;
	}
	while (argv[argc]) {
		free (argv[argc++]);
	}
	free (argv);
}

Project: radare2
File: test_str.c

bool test_r_str_char_count(void) {
	mu_assert_eq (r_str_char_count ("poop", 'p'), 2, "number of p in poop");
	mu_end;
}

Project: radare2
File: str.c

R_API char *r_str_escape_utf16be(const char *buf, int buf_size, bool show_asciidot, bool esc_bslash) {
	return r_str_escape_utf (buf, buf_size, R_STRING_ENC_UTF16BE, show_asciidot, esc_bslash, false);
}

Project: radare2
File: str.c

R_API RList *r_str_split_list(char *str, const char *c, int n)  {
	r_return_val_if_fail (str && c, NULL);
	RList *lst = r_list_newf (NULL);
	char *aux = str;
	int i = 0;
	char  *e = aux;
	for (;e;) {
		e = strstr (aux, c);
		if (n > 0) {
			if (++i > n) {
				r_list_append (lst, aux);
				break;
			}
		}
		if (e) {
			*e++ =  0;
		}
		r_str_trim (aux);
		r_list_append (lst, aux);
		aux = e;
	}
	return lst;
}

Project: radare2
File: test_str.c

bool test_r_str_unescape(void) {
	char buf[] = "Hello\\x31World\\n";
	r_str_unescape (buf);
	mu_assert_streq (buf, "Hello1World\n", "unescaped");
	mu_end;
}

Project: radare2
File: str.c

R_API const char *r_str_ansi_chrn(const char *str, size_t n) {
	int len, i, li;
	for (li = i = len = 0; str[i] && (n != len); i++) {
		size_t chlen = __str_ansi_length (str + i);
		if (chlen > 1) {
			i += chlen - 1;
		} else {
			if ((str[i] & 0xc0) != 0x80) {
				len++;
			}
			li = i;
		}
	}
	return str + li;
}

Project: radare2
File: sys.c

R_API int r_sys_cmd(const char *str) {
	if (r_sandbox_enable (0)) {
		return false;
	}
	return r_sandbox_system (str, 1);
}

Project: radare2
File: test_str.c

bool test_r_str_rchr(void) {
	const char* test = "raddddare2d";
	const char* out = r_str_rchr (test, NULL, '2');
	mu_assert_streq (out, "2d", "pointer to last p in range in raddddare2d");
	out = r_str_rchr (test, NULL, 'p');
	if (out) {
		mu_assert ("non NULL value returned", 0);
	}
	out = test + 9;
	out = r_str_rchr (test, out, 'd');
	mu_assert_streq (out, "dare2d", "pointer to last d in range in raddddare2d");
	out = test + strlen (test);
	out = r_str_rchr (test, out, 'p');
	if (out) {
		mu_assert ("non NULL value of out", 0);
	}
	mu_end;
}

Project: radare2
File: disk.c

SDB_API bool sdb_disk_create(Sdb* s) {
	int nlen;
	char *str;
	const char *dir;
	if (!s || s->fdump >= 0) {
		return false; // cannot re-create
	}
	if (!s->dir && s->name) {
		s->dir = strdup (s->name);
	}
	dir = s->dir ? s->dir : "./";
	R_FREE (s->ndump);
	nlen = strlen (dir);
	str = malloc (nlen + 5);
	if (!str) {
		return false;
	}
	memcpy (str, dir, nlen + 1);
	r_sys_mkdirp (str);
	memcpy (str + nlen, ".tmp", 5);
	if (s->fdump != -1) {
		close (s->fdump);
	}
#if __SDB_WINDOWS__ && UNICODE
	wchar_t *wstr = r_sys_conv_utf8_to_utf16 (str);
	if (wstr) {
		s->fdump = _wopen (wstr, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, SDB_MODE);
		free (wstr);
	} else {
		s->fdump = -1;
	}
#else
	s->fdump = open (str, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, SDB_MODE);
#endif
	if (s->fdump == -1) {
		eprintf ("sdb: Cannot open '%s' for writing.\n", str);
		free (str);
		return false;
	}
	cdb_make_start (&s->m, s->fdump);
	s->ndump = str;
	return true;
}

Project: radare2
File: disk.c

SDB_API bool sdb_disk_unlink (Sdb *s) {
	return (s->dir && *(s->dir) && unlink (s->dir) != -1);
}

Project: radare2
File: str.c

R_API char *r_str_path_escape(const char *path) {
	char *str;
	int dest_i = 0, src_i = 0;

	if (!path) {
		return NULL;
	}
	// Worst case when every character need to be escaped
	str = malloc ((2 * strlen (path) + 1) * sizeof (char));
	if (!str) {
		return NULL;
	}

	for (src_i = 0; path[src_i] != '\0'; src_i++) {
		char c = path[src_i];
		switch (c) {
		case ' ':
			str[dest_i++] = '\\';
			str[dest_i++] = c;
			break;
		default:
			str[dest_i++] = c;
			break;
		}
	}

	str[dest_i] = '\0';
	return realloc (str, (strlen (str) + 1) * sizeof (char));
}

Project: radare2
File: str.c

R_API char *r_str_format_msvc_argv(size_t argc, const char **argv) {
	RStrBuf sb;
	r_strbuf_init (&sb);

	size_t i;
	for (i = 0; i < argc; i++) {
		if (i > 0) {
			r_strbuf_append (&sb, " ");
		}
		const char *arg = argv[i];
		bool must_escape = strchr (arg, '\"') != NULL;
		bool must_quote = strpbrk (arg, " \t") != NULL || !*arg;
		if (!must_escape && must_quote && *arg && arg[strlen (arg) - 1] == '\\') {
			// if the last char is a bs and we would quote it, we must also escape
			must_escape = true;
		}
		if (must_quote) {
			r_strbuf_append (&sb, "\"");
		}
		if (must_escape) {
			size_t bs_count = 0; // bullshit counter
			for (; *arg; arg++) {
				switch (*arg) {
				case '\"':
					for (; bs_count; bs_count--) {
						// backslashes must be escaped iff they precede a "
						// so just duplicate the number of backslashes already printed
						r_strbuf_append (&sb, "\\");
					}
					r_strbuf_append (&sb, "\\\"");
					break;
				case '\\':
					bs_count++;
					r_strbuf_append (&sb, "\\");
					break;
				default:
					bs_count = 0;
					r_strbuf_append_n (&sb, arg, 1);
					break;
				}
			}
			if (must_quote) {
				// there will be a quote after this so we have to escape bs here as well
				for (; bs_count; bs_count--) {
					r_strbuf_append (&sb, "\\");
				}
			}
		} else {
			r_strbuf_append (&sb, arg);
		}
		if (must_quote) {
			r_strbuf_append (&sb, "\"");
		}
	}

	return r_strbuf_drain_nofree (&sb);
}

Project: radare2
File: str.c

R_API char *r_str_newf(const char *fmt, ...) {
	va_list ap, ap2;

	va_start (ap, fmt);
	if (!strchr (fmt, '%')) {
		va_end (ap);
		return strdup (fmt);
	}
	va_copy (ap2, ap);
	int ret = vsnprintf (NULL, 0, fmt, ap2);
	ret++;
	char *p = calloc (1, ret);
	if (p) {
		(void)vsnprintf (p, ret, fmt, ap);
	}
	va_end (ap2);
	va_end (ap);
	return p;
}

Project: radare2
File: str.c

R_API const char *r_strstr_ansi(const char *a, const char *b) {
	const char *ch, *p = a;
	do {
		ch = strchr (p, '\x1b');
		if (ch) {
			const char *v = r_str_nstr (p, b, ch - p);
			if (v) {
				return v;
			}
			p = ch + __str_ansi_length (ch);
		}
	} while (ch);
	return strstr (p, b);
}

Project: radare2
File: str.c

R_API int r_str_word_count(const char *string) {
	const char *text, *tmp;
	int word;

	for (text = tmp = string; *text && IS_SEPARATOR (*text); text++) {
		;
	}
	for (word = 0; *text; word++) {
		for (; *text && !IS_SEPARATOR (*text); text++) {
			;
		}
		for (tmp = text; *text && IS_SEPARATOR (*text); text++) {
			;
		}
	}
	return word;
}

Project: radare2
File: test_str.c

bool test_r_str_ichr(void) {
	char* test = "rrrrrradare2";
	char* out = r_str_ichr (test, 'r');
	mu_assert_streq (out, "adare2",
			"string after the first non-r character in rrrrrradare2");
	mu_end;
}

Project: radare2
File: str.c

R_API void r_str_filter_zeroline(char *str, int len) {
	int i;
	for (i = 0; i < len && str[i]; i++) {
		if (str[i] == '\n' || str[i] == '\r') {
			break;
		}
		if (!IS_PRINTABLE (str[i])) {
			break;
		}
	}
	str[i] = 0;
}

Project: radare2
File: str.c

R_API char *r_str_r2_prefix(const char *str) {
	return r_str_newf ("%s%s%s", r_sys_prefix (NULL), R_SYS_DIR, str);
}

Project: radare2
File: socket.c

R_API int r_socket_close_fd (RSocket *s) {
	return -1;
}

Project: radare2
File: str.c

R_API wchar_t* r_str_mb_to_wc(const char *buf) {
	if (!buf) {
		return NULL;
	}
	return r_str_mb_to_wc_l (buf, strlen (buf));
}

Project: radare2
File: socket.c

R_API bool r_socket_spawn (RSocket *s, const char *cmd, unsigned int timeout) {
	return -1;
}

Project: radare2
File: str.c

R_API const char *r_str_last(const char *str, const char *ch) {
	char *ptr, *end = NULL;
	if (!str || !ch) {
		return NULL;
	}
	do {
		ptr = strstr (str, ch);
		if (!ptr) {
			break;
		}
		end = ptr;
		str = ptr + 1;
	} while (true);
	return end;
}

Project: radare2
File: str.c

R_API bool r_str_endswith(const char *str, const char *needle) {
	r_return_val_if_fail (str && needle, false);
	if (!*needle) {
		return true;
	}
	int slen = strlen (str);
	int nlen = strlen (needle);
	if (!slen || !nlen || slen < nlen) {
		return false;
	}
	return !strcmp (str + (slen - nlen), needle);
}

Project: radare2
File: str.c

R_API char *r_str_replace_in(char *str, ut32 sz, const char *key, const char *val, int g) {
	if (!str || !key || !val) {
		return NULL;
	}
	char *heaped = r_str_replace (strdup (str), key, val, g);
	if (heaped) {
		strncpy (str, heaped, sz);
		free (heaped);
	}
	return str;
}

Project: radare2
File: socket.c

R_API RSocket *r_socket_new_from_fd (int fd) {
	return NULL;
}

Project: radare2
File: disk.c

static bool r_sys_mkdir(const char *path) {
	LPTSTR path_ = r_sys_conv_utf8_to_utf16 (path);
	bool ret = CreateDirectory (path_, NULL);

	free (path_);
	return ret;
}

Project: radare2
File: str.c

R_API int r_str_arg_unescape(char *arg) {
	int dest_i = 0, src_i = 0;
	if (!arg) {
		return 0;
	}
	for (src_i = 0; arg[src_i] != '\0'; src_i++) {
		char c = arg[src_i];
		if (c == '\\') {
			if (arg[++src_i] == '\0') {
				break;
			}
			arg[dest_i++] = arg[src_i];
		} else {
			arg[dest_i++] = c;
		}
	}
	arg[dest_i] = '\0';
	return dest_i;
}

Project: radare2
File: str.c

R_API int r_str_fmtargs(const char *fmt) {
	int n = 0;
	while (*fmt) {
		if (*fmt == '%') {
			if (fmt[1] == '*') {
				n++;
			}
			n++;
		}
		fmt++;
	}
	return n;
}

Project: radare2
File: test_str.c

bool test_r_sub_str_rchr(void) {
	const char* test = "raddddare2d";
	const char* out = r_sub_str_rchr (test, 1, 8, 'd');
	mu_assert_streq (out, "ddddare2d", "pointer to first d in range in radddddare2d");
	mu_end;
}

Project: radare2
File: str.c

R_API char *r_str_escape_utf8_keep_printable(const char *buf, bool show_asciidot, bool esc_bslash) {
	return r_str_escape_utf (buf, -1, R_STRING_ENC_UTF8, show_asciidot, esc_bslash, true);
}

Project: radare2
File: socket_http.c

void main () {
	int ret;
	char *p = r_socket_http_post ("http://www.radare.org/y/index.php", "a=b", &ret);
	printf ("%s\n", p);
}

Project: radare2
File: str.c

R_API char *r_str_replace_icase(char *str, const char *key, const char *val, int g, int keep_case) {
	r_return_val_if_fail (str && key && val, NULL);

	int off, i, klen, vlen, slen;
	char *newstr, *p = str;
	klen = strlen (key);
	vlen = strlen (val);

	slen = strlen (str);
	for (i = 0; i < slen;) {
		p = (char *)r_str_casestr (str + i, key);
		if (!p) {
			break;
		}
		off = (int)(size_t) (p - str);
		if (vlen != klen) {
			int tlen = slen - (off + klen);
			slen += vlen - klen;
			if (vlen > klen) {
				newstr = realloc (str, slen + 1);
				if (!newstr) {
					goto alloc_fail;
				}
				str = newstr;
			}
			p = str + off;
			memmove (p + vlen, p + klen, tlen + 1);
		}

		if (keep_case) {
			char *tmp_val = strdup (val);
			char *str_case = r_str_ndup (p, klen);
			if (!tmp_val || !str_case) {
				free (tmp_val);
				free (str_case);
				goto alloc_fail;
			}
			tmp_val = r_str_replace_icase (tmp_val, key, str_case, 0, 0);
			free (str_case);
			if (!tmp_val) {
				goto alloc_fail;
			}
			memcpy (p, tmp_val, vlen);
			free (tmp_val);
		} else {
			memcpy (p, val, vlen);
		}

		i = off + vlen;
		if (!g) {
			break;
		}
	}
	return str;

alloc_fail:
	eprintf ("alloc fail\n");
	free (str);
	return NULL;
}

Project: radare2
File: str.c

static void trimbits(char *b) {
	const int len = strlen (b);
	char *one = strchr (b, '1');
	int pos = one ? (int)(size_t)(one - b) : len - 1;
	pos = (pos / 8) * 8;
	memmove (b, b + pos, len - pos + 1);
}

Project: radare2
File: socket_http.c

static char *http_get_w32(const char *url, int *code, int *rlen) {
	HINTERNET hInternet = InternetOpenA ("radare2 "R2_VERSION, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
	if (!hInternet) {
		r_sys_perror ("InternetOpenA");
		return NULL;
	}
	HINTERNET hOpenUrl = InternetOpenUrlA (hInternet, url, NULL, 0, 0, 0);
	if (!hOpenUrl) {
		r_sys_perror ("InternetOpenUrlA");
		InternetCloseHandle (hInternet);
		return NULL;
	}

	char *ret = NULL;
	size_t read_sz = 0x100000;
	DWORD r = 0, w = 0;
	bool res = true;
	do {
		w += r;
		if (!res && GetLastError () == ERROR_INSUFFICIENT_BUFFER) {
			read_sz *= 2;
		}
		char *tmp = realloc (ret, read_sz + w);
		if (!tmp) {
			R_FREE (ret);
			goto exit;
		}
		ret = tmp;
	} while (!(res = InternetReadFile (hOpenUrl, ret + w, read_sz, &r)) || r);

	if (w) {
		char *tmp = realloc (ret, (size_t)w + 1);
		if (tmp) {
			ret = tmp;
			ret[w] = 0;
		} else {
			R_FREE (ret);
		}
	} else {
		R_FREE (ret);
	}

exit:
	if (rlen) {
		*rlen = w;
	}
	if (code && w) {
		*code = 200;
	}
	InternetCloseHandle (hInternet);
	InternetCloseHandle (hOpenUrl);
	return ret;
}

Project: radare2
File: str.c

R_API const char *r_str_lchr(const char *str, char chr) {
	if (str) {
		int len = strlen (str);
		for (; len >= 0; len--) {
			if (str[len] == chr) {
				return str + len;
			}
		}
	}
	return NULL;
}

Project: radare2
File: test_str.c

bool test_r_str_ansi_len(void) {
	int len;

	len = r_str_ansi_len ("radare2");
	mu_assert_eq (len, 7, "len(ascii only)");

	len = r_str_ansi_len ("r\x1b[38;2;208;80;0madare2");
	mu_assert_eq (len, 7, "len(ascii + ansi ending with m)");

	len = r_str_ansi_len ("r\x1b[0Jadare2");
	mu_assert_eq (len, 7, "len(ascii + ansi ending with J)");

	len = r_str_ansi_len ("r\x1b[42;42Hadare2");
	mu_assert_eq (len, 7, "len(ascii + ansi ending with H)");

	len = r_str_ansi_len ("r\xc3\xa4""dare2");
	mu_assert_eq (len, 8, "len(ascii + 2 byte utf-8 counted as 2 chars)");

	len = r_str_ansi_len ("radar\xe2\x82\xac""2");
	mu_assert_eq (len, 9, "len(ascii + 3 byte utf-8 counted as 3 chars)");

	len = r_str_ansi_len ("radar\xf0\x9d\x84\x9e""2");
	mu_assert_eq (len, 10, "len(ascii + 4 byte utf-8 counted as 4 chars)");

	mu_end;
}

Project: radare2
File: sys.c

R_API int r_sys_setenv(const char *key, const char *value) {
	if (!key) {
		return 0;
	}
#if __UNIX__
	if (!value) {
		unsetenv (key);
		return 0;
	}
	return setenv (key, value, 1);
#elif __WINDOWS__
	LPTSTR key_ = r_sys_conv_utf8_to_win (key);
	LPTSTR value_ = r_sys_conv_utf8_to_win (value);
	int ret = SetEnvironmentVariable (key_, value_);
	if (!ret) {
		r_sys_perror ("r_sys_setenv/SetEnvironmentVariable");
	}
	free (key_);
	free (value_);
	return ret ? 0 : -1;
#else
#warning r_sys_setenv : unimplemented for this platform
	return 0;
#endif
}

Project: radare2
File: socket_http.c

static size_t socket_slurp(RSocket *s, RBuffer *buf) {
	size_t i;
	if (r_socket_ready (s, 1, 0) != 1) {
		return 0;
	}
	r_socket_block_time (s, 1, 0, 1000);
	for (i = 0; i < SOCKET_HTTP_MAX_HEADER_LENGTH; i += 1) {
		ut8 c;
		int olen = r_socket_read_block (s, &c, 1);
		if (olen != 1) {
			r_buf_append_bytes (buf, (ut8 *)"", 1);
			break;
		}
		r_buf_append_bytes (buf, &c, 1);
	}
	return i;
}

Project: radare2
File: str.c

R_API char *r_str_utf16_encode(const char *s, int len) {
	int i;
	char ch[4], *d, *od, *tmp;
	if (!s) {
		return NULL;
	}
	if (len < 0) {
		len = strlen (s);
	}
	if ((len * 7) + 1 < len) {
		return NULL;
	}
	od = d = malloc (1 + (len * 7));
	if (!d) {
		return NULL;
	}
	for (i = 0; i < len; s++, i++) {
		if (*s == '\\') {
			*d++ = '\\';
			*d++ = '\\';
		} else if (*s == '"') {
			*d++ = '\\';
			*d++ = '"';
		} else if ((*s >= 0x20) && (*s <= 126)) {
			*d++ = *s;
		} else {
			*d++ = '\\';
			//	*d++ = '\\';
			*d++ = 'u';
			*d++ = '0';
			*d++ = '0';
			snprintf (ch, sizeof (ch), "%02x", 0xff & ((ut8)*s));
			*d++ = ch[0];
			*d++ = ch[1];
		}
	}
	*d = 0;
	tmp = realloc (od, strlen (od) + 1); // FIT
	if (!tmp) {
		free (od);
		return NULL;
	}
	return tmp;
}

Project: radare2
File: str.c

R_API char *r_str_scale(const char *s, int w, int h) {
	// count lines and rows in (s) string
	// compute how many lines we should remove or combine
	// return a string containing
	// for now this function is ascii only (no utf8 or ansi escapes)
	RListIter *iter;
	char *line;
	char *str = strdup (s);
	RList *lines = r_str_split_list (str, "\n", 0);
	int i, j;
	int rows = 0;
	int maxcol = 0;

	rows = r_list_length (lines);
	r_list_foreach (lines, iter, line) {
		maxcol = R_MAX (strlen (line), maxcol);
	}

	RList *out = r_list_newf (free);

	int curline = -1;
	char *linetext = (char*)r_str_pad (' ', w);
	for (i = 0; i < h; i++) {
		int zoomedline = i * ((float)rows / h);
		const char *srcline = r_list_get_n (lines, zoomedline);
		int cols = strlen (srcline);
		for (j = 0; j < w; j++) {
			int zoomedcol = j * ( (float)cols / w);
			linetext[j] = srcline[zoomedcol];
		}
		if (curline != zoomedline) {
			r_list_append (out, strdup (linetext));
			curline = zoomedline;
		}
		memset (linetext, ' ', w);
	}
	free (str);
	return r_str_list_join (out, "\n");
}

Project: radare2
File: str.c

R_API const char *r_sub_str_rchr(const char *str, int start, int end, char chr) {
	while (str[start] != chr && start < end) {
		start++;
	}
	return str[start] == chr ? str + start : NULL;
}

Project: radare2
File: str.c

R_API void r_str_filter(char *str, int len) {
	size_t i;
	if (len < 1) {
		len = strlen (str);
	}
	for (i = 0; i < len; i++) {
		if (!IS_PRINTABLE (str[i])) {
			str[i] = '.';
		}
	}
}

Project: radare2
File: str.c

static char *r_str_escape_utf(const char *buf, int buf_size, RStrEnc enc, bool show_asciidot, bool esc_bslash, bool keep_printable) {
	char *new_buf, *q;
	const char *p, *end;
	RRune ch;
	int i, len, ch_bytes;

	if (!buf) {
		return NULL;
	}
	switch (enc) {
	case R_STRING_ENC_UTF16LE:
	case R_STRING_ENC_UTF16BE:
	case R_STRING_ENC_UTF32LE:
	case R_STRING_ENC_UTF32BE:
		if (buf_size < 0) {
			return NULL;
		}
		if (enc == R_STRING_ENC_UTF16LE || enc == R_STRING_ENC_UTF16BE) {
			end = (char *)r_mem_mem_aligned ((ut8 *)buf, buf_size, (ut8 *)"\0\0", 2, 2);
		} else {
			end = (char *)r_mem_mem_aligned ((ut8 *)buf, buf_size, (ut8 *)"\0\0\0\0", 4, 4);
		}
		if (!end) {
			end = buf + buf_size - 1; /* TODO: handle overlong strings properly */
		}
		len = end - buf;
		break;
	default:
		len = strlen (buf);
		end = buf + len;
	}
	/* Worst case scenario, we convert every byte to \xhh */
	new_buf = malloc (1 + (len * 4));
	if (!new_buf) {
		return NULL;
	}
	p = buf;
	q = new_buf;
	while (p < end) {
		switch (enc) {
		case R_STRING_ENC_UTF16LE:
		case R_STRING_ENC_UTF16BE:
		case R_STRING_ENC_UTF32LE:
		case R_STRING_ENC_UTF32BE:
			if (enc == R_STRING_ENC_UTF16LE || enc == R_STRING_ENC_UTF16BE) {
				ch_bytes = r_utf16_decode ((ut8 *)p, end - p, &ch, enc == R_STRING_ENC_UTF16BE);
			} else {
				ch_bytes = r_utf32_decode ((ut8 *)p, end - p, &ch, enc == R_STRING_ENC_UTF32BE);
			}
			if (ch_bytes == 0) {
				p++;
				continue;
			}
			break;
		default:
			ch_bytes = r_utf8_decode ((ut8 *)p, end - p, &ch);
			if (ch_bytes == 0) {
				ch_bytes = 1;
			}
		}
		if (show_asciidot && !IS_PRINTABLE(ch)) {
			*q++ = '.';
		} else if (ch_bytes > 1) {
			if (keep_printable) {
				q += r_utf8_encode ((ut8 *)q, ch);
			} else {
				*q++ = '\\';
				*q++ = ch_bytes == 4 ? 'U' : 'u';
				for (i = ch_bytes == 4 ? 6 : 2; i >= 0; i -= 2) {
					*q++ = "0123456789abcdef"[ch >> 4 * (i + 1) & 0xf];
					*q++ = "0123456789abcdef"[ch >> 4 * i & 0xf];
				}
			}
		} else {
			int offset = enc == R_STRING_ENC_UTF16BE ? 1 : enc == R_STRING_ENC_UTF32BE ? 3 : 0;
			r_str_byte_escape (p + offset, &q, false, false, esc_bslash);
		}
		switch (enc) {
		case R_STRING_ENC_UTF16LE:
		case R_STRING_ENC_UTF16BE:
			p += ch_bytes < 2 ? 2 : ch_bytes;
			break;
		case R_STRING_ENC_UTF32LE:
		case R_STRING_ENC_UTF32BE:
			p += 4;
			break;
		default:
			p += ch_bytes;
		}
	}
	*q = '\0';
	return new_buf;
}

Project: radare2
File: socket.c

R_API RSocket *r_socket_accept(RSocket *s) {
	RSocket *sock;
	socklen_t salen = sizeof (s->sa);
	if (!s) {
		return NULL;
	}
	sock = R_NEW0 (RSocket);
	if (!sock) {
		return NULL;
	}
	//signal (SIGPIPE, SIG_DFL);
	sock->fd = accept (s->fd, (struct sockaddr *)&s->sa, &salen);
	if (sock->fd == R_INVALID_SOCKET) {
		if (errno != EWOULDBLOCK) {
			// not just a timeout
			r_sys_perror ("accept");
		}
		free (sock);
		return NULL;
	}
#if HAVE_LIB_SSL
	sock->is_ssl = s->is_ssl;
	if (sock->is_ssl) {
		sock->sfd = NULL;
		sock->ctx = NULL;
		sock->bio = NULL;
		BIO *sbio = BIO_new_socket (sock->fd, BIO_NOCLOSE);
		sock->sfd = SSL_new (s->ctx);
		SSL_set_bio (sock->sfd, sbio, sbio);
		if (SSL_accept (sock->sfd) <= 0) {
			r_socket_free (sock);
			return NULL;
		}
		sock->bio = BIO_new (BIO_f_buffer ());
		sbio = BIO_new (BIO_f_ssl ());
		BIO_set_ssl (sbio, sock->sfd, BIO_CLOSE);
		BIO_push (sock->bio, sbio);
	}
#else
	sock->is_ssl = 0;
#endif
	return sock;
}

Project: radare2
File: str.c

R_API void r_str_remove_char(char *str, char c) {
	while (*str) {
		if (*str == c) {
			memmove (str, str + 1, strlen (str + 1) + 1);
			continue;
		}
		str++;
	}
}

Project: radare2
File: socket.c

R_API int r_socket_block_time(RSocket *s, int block, int sec, int usec) {
#if __UNIX__
	int ret, flags;
#endif
	if (!s) {
		return false;
	}
#if __UNIX__
	flags = fcntl (s->fd, F_GETFL, 0);
	if (flags < 0) {
		return false;
	}
	ret = fcntl (s->fd, F_SETFL, block?
			(flags & ~O_NONBLOCK):
			(flags | O_NONBLOCK));
	if (ret < 0) {
		return false;
	}
#elif __WINDOWS__
	ioctlsocket (s->fd, FIONBIO, (u_long FAR*)&block);
#endif
	if (sec > 0 || usec > 0) {
		struct timeval tv = {sec, usec};
		if (setsockopt (s->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof (tv)) < 0) {
			return false;
		}
	}
	return true;
}

Project: radare2
File: test_str.c

bool test_r_str_constpool(void) {
	RStrConstPool pool;
	bool s = r_str_constpool_init (&pool);
	mu_assert ("pool init success", s);

	const char *a_ref = "deliverance";
	const char *a_pooled = r_str_constpool_get (&pool, a_ref);
	mu_assert_ptrneq (a_pooled, a_ref, "pooled != ref");
	mu_assert_streq (a_pooled, a_ref, "pooled == ref (strcmp)");
	const char *a_pooled2 = r_str_constpool_get (&pool, a_ref);
	mu_assert_ptreq (a_pooled2, a_pooled, "same on re-get");
	char *a_ref_cpy = strdup (a_ref);
	a_pooled2 = r_str_constpool_get (&pool, a_ref_cpy);
	free (a_ref_cpy);
	mu_assert_ptreq (a_pooled2, a_pooled, "same on re-get with different ptr");

	const char *b_ref = "damnation";
	const char *b_pooled = r_str_constpool_get (&pool, b_ref);
	mu_assert_ptrneq (b_pooled, b_ref, "pooled != ref (second)");
	mu_assert_streq (b_pooled, b_ref, "pooled == ref (strcmp, second)");

	r_str_constpool_fini (&pool);
	mu_end;
}

Project: radare2
File: str.c

R_API const char * r_str_tok(const char *str1, const char b, size_t len) {
	const char *p = str1;
	size_t i = 0;
	if (!p || !*p) {
		return p;
	}
	if (len == -1) {
		len = strlen (str1);
	}
	for ( ; i < len; i++,p++) {
		if (*p == b) {
			break;
		}
	}
	if (i == len) {
		p = NULL;
	}
	return p;
}

Project: radare2
File: sys.c

R_API int r_sys_crash_handler(const char *cmd) {
#ifndef __WINDOWS__
	int sig[] = { SIGINT, SIGSEGV, SIGBUS, SIGQUIT, SIGHUP, 0 };

	if (!checkcmd (cmd)) {
		return false;
	}
#ifdef HAVE_BACKTRACE
	void *array[1];
	/* call this outside of the signal handler to init it safely */
	backtrace (array, 1);
#endif

	free (crash_handler_cmd);
	crash_handler_cmd = strdup (cmd);

	r_sys_sigaction (sig, signal_handler);
#else
#pragma message ("r_sys_crash_handler : unimplemented for this platform")
#endif
	return true;
}

Project: radare2
File: str.c

R_API char *r_str_appendch(char *x, char y) {
	char b[2] = { y, 0 };
	return r_str_append (x, b);
}

Project: radare2
File: str.c

R_API char *r_str_arg_escape(const char *arg) {
	char *str;
	int dest_i = 0, src_i = 0;
	if (!arg) {
		return NULL;
	}
	str = malloc ((2 * strlen (arg) + 1) * sizeof (char)); // Worse case when every character need to be escaped
	if (!str) {
		return NULL;
	}
	for (src_i = 0; arg[src_i] != '\0'; src_i++) {
		char c = arg[src_i];
		switch (c) {
		case '\'':
		case '"':
		case '\\':
		case ' ':
			str[dest_i++] = '\\';
			str[dest_i++] = c;
			break;
		default:
			str[dest_i++] = c;
			break;
		}
	}
	str[dest_i] = '\0';
	return realloc (str, (strlen(str)+1) * sizeof (char));
}

Project: radare2
File: socket.c

R_API int r_socket_flush(RSocket *s) {
	return -1;
}

Project: radare2
File: str.c

R_API int r_str_replace_char_once(char *s, int a, int b) {
	return r_str_replace_ch (s, a, b, false);
}

Project: radare2
File: socket.c

R_API RSocket *r_socket_accept(RSocket *s) {
	return NULL;
}

Project: radare2
File: socket.c

R_API int r_socket_close(RSocket *s) {
	int ret = false;
	if (!s) {
		return false;
	}
	if (s->fd != R_INVALID_SOCKET) {
#if __UNIX__
		shutdown (s->fd, SHUT_RDWR);
#endif
#if __WINDOWS__
		// https://msdn.microsoft.com/en-us/library/windows/desktop/ms740481(v=vs.85).aspx
		shutdown (s->fd, SD_SEND);
		if (r_socket_ready (s, 0, 250)) {
			do {
				char buf = 0;
				ret = recv (s->fd, &buf, 1, 0);
			} while (ret != 0 && ret != SOCKET_ERROR);
		}
		ret = closesocket (s->fd);
#else
		ret = close (s->fd);
#endif
		s->fd = R_INVALID_SOCKET;
	}
#if HAVE_LIB_SSL
	if (s->is_ssl && s->sfd) {
		SSL_free (s->sfd);
		s->sfd = NULL;
	}
#endif
	return ret;
}

Project: radare2
File: str.c

R_API bool r_str_is_printable_limited(const char *str, int size) {
	while (size > 0 && *str) {
		int ulen = r_utf8_decode ((const ut8*)str, strlen (str), NULL);
		if (ulen > 1) {
			str += ulen;
			continue;
		}
		if (!IS_PRINTABLE (*str)) {
			return false;
		}
		str++;
		size--;
	}
	return true;
}

Project: radare2
File: sys.c

R_API bool r_sys_mkdir(const char *dir) {
	bool ret;

	if (r_sandbox_enable (0)) {
		return false;
	}
#if __WINDOWS__
	LPTSTR dir_ = r_sys_conv_utf8_to_win (dir);

	ret = CreateDirectory (dir_, NULL) != 0;
	free (dir_);
#else
	ret = mkdir (dir, 0755) != -1;
#endif
	return ret;
}

Project: radare2
File: str.c

R_API char *r_str_repeat(const char *ch, int sz) {
	int i;
	if (sz < 0) {
		sz = 0;
	}
	if (sz == 0) {
		return strdup ("");
	}
	RStrBuf *buf = r_strbuf_new (ch);
	for (i = 1; i < sz; i++) {
		r_strbuf_append (buf, ch);
	}
	return r_strbuf_drain (buf);
}

Project: radare2
File: test_str.c

bool test_r_str_utf8_charsize(void) {
	char s[16] = "\x61\xc3\xa1\xe6\x97\xa5\xf0\x9f\x91\x8c\xf0\x9f\x91\x8c\x8c"; // aá日👌
	int sz;

	sz = r_str_utf8_charsize (s);
	mu_assert_eq (sz, 1, "1 byte UTF-8");

	sz = r_str_utf8_charsize (s + 1);
	mu_assert_eq (sz, 2, "2 byte UTF-8");

	sz = r_str_utf8_charsize (s + 3);
	mu_assert_eq (sz, 3, "3 byte UTF-8");

	sz = r_str_utf8_charsize (s + 6);
	mu_assert_eq (sz, 4, "4 byte UTF-8");

	sz = r_str_utf8_charsize (s + 10);
	mu_assert_eq (sz, 0, "Malformed UTF-8");

	mu_end;
}

Project: radare2
File: str.c

R_API ut64 r_str_hash64(const char *s) {
	ut64 len, h = 5381;
	if (!s) {
		return 0;
	}
	for (len = strlen (s); len > 0; len--) {
		h = (h ^ (h << 5)) ^ *s++;
	}
	return h;
}

Project: radare2
File: str.c

R_API const char *r_str_closer_chr(const char *b, const char *s) {
	const char *a;
	while (*b) {
		for (a = s; *a; a++) {
			if (*b == *a) {
				return b;
			}
		}
		b++;
	}
	return NULL;
}

Project: radare2
File: str.c

R_API int r_str_binstr2bin(const char *str, ut8 *out, int outlen) {
	int n, i, j, k, ret, len;
	len = strlen (str);
	for (n = i = 0; i < len; i += 8) {
		ret = 0;
		while (str[i]==' ') {
			str++;
		}
		if (i + 7 < len) {
			for (k = 0, j = i + 7; j >= i; j--, k++) {
				// INVERSE for (k=0,j=i; j<i+8; j++,k++) {
				if (str[j] == ' ') {
					//k--;
					continue;
				}
				//		printf ("---> j=%d (%c) (%02x)\n", j, str[j], str[j]);
				if (str[j] == '1') {
					ret|=1 << k;
				} else if (str[j] != '0') {
					return n;
				}
			}
		}
	//	printf ("-======> %02x\n", ret);
		out[n++] = ret;
		if (n == outlen) {
			return n;
		}
	}
	return n;
}

Project: radare2
File: socket.c

R_API int r_socket_gets(RSocket *s, char *buf,	int size) {
	return -1;
}

Project: radare2
File: sys.c

static void signal_handler(int signum) {
	char cmd[1024];
	if (!crash_handler_cmd) {
		return;
	}
	snprintf (cmd, sizeof(cmd) - 1, crash_handler_cmd, getpid ());
	r_sys_backtrace ();
	exit (r_sys_cmd (cmd));
}

Project: radare2
File: str.c

R_API char *r_str_appendlen(char *ptr, const char *string, int slen) {
	char *msg = r_str_newlen (string, slen);
	char *ret = r_str_append (ptr, msg);
	free (msg);
	return ret;
}

Project: radare2
File: str.c

static char *strchr_skip_color_codes(const char *s, int c) {
	int i = 0;
	for (i = 0; s[i]; i++) {
		while (s[i] && s[i] == 0x1b) {
			while (s[i] && s[i] != 'm') {
				i++;
			}
			if (s[i]) {
				i++;
			}
		}
		if (!s[i] || s[i] == (char)c) {
			return (char*)s + i;
		}
	}
	return NULL;
}

Project: radare2
File: str.c

R_API int r_str_rwx(const char *str) {
	int ret = atoi (str);
	if (!ret) {
		ret |= strchr (str, 'm') ? 16 : 0;
		ret |= strchr (str, 'r') ? 4 : 0;
		ret |= strchr (str, 'w') ? 2 : 0;
		ret |= strchr (str, 'x') ? 1 : 0;
	} else if (ret < 0 || ret >= R_ARRAY_SIZE (rwxstr)) {
		ret = 0;
	}
	return ret;
}

Project: radare2
File: str.c

R_API char *r_str_escape_sh(const char *buf) {
	r_return_val_if_fail (buf, NULL);
	char *new_buf = malloc (1 + strlen (buf) * 2);
	if (!new_buf) {
		return NULL;
	}
	const char *p = buf;
	char *q = new_buf;
	while (*p) {
		switch (*p) {
#if __UNIX__
		case '$':
		case '`':
#endif
		case '\\':
		case '"':
			*q++ = '\\';
			/* FALLTHRU */
		default:
			*q++ = *p++;
			break;
		}
	}
	*q = '\0';
	return new_buf;
}

Project: radare2
File: str.c

R_API char *r_str_escape_utf8_for_json(const char *buf, int buf_size) {
	char *new_buf, *q;
	const char *p, *end;
	RRune ch;
	int i, len, ch_bytes;

	if (!buf) {
		return NULL;
	}
	len = buf_size < 0 ? strlen (buf) : buf_size;
	end = buf + len;
	/* Worst case scenario, we convert every byte to \u00hh */
	new_buf = malloc (1 + (len * 6));
	if (!new_buf) {
		return NULL;
	}
	p = buf;
	q = new_buf;
	while (p < end) {
		ch_bytes = r_utf8_decode ((ut8 *)p, end - p, &ch);
		if (ch_bytes == 1) {
			switch (*p) {
			case '\n':
				*q++ = '\\';
				*q++ = 'n';
				break;
			case '\r':
				*q++ = '\\';
				*q++ = 'r';
				break;
			case '\\':
				*q++ = '\\';
				*q++ = '\\';
				break;
#if 0
			case '/': /* has 2-char esc seq in JSON spec, but escaping is optional */
				*q++ = '\\';
				*q++ = '/';
				break;
#endif
			case '\t':
				*q++ = '\\';
				*q++ = 't';
				break;
			case '"' :
				*q++ = '\\';
				*q++ = '"';
				break;
			case '\f':
				*q++ = '\\';
				*q++ = 'f';
				break;
			case '\b':
				*q++ = '\\';
				*q++ = 'b';
				break;
			default:
				if (!IS_PRINTABLE (*p)) {
					*q++ = '\\';
					*q++ = 'u';
					*q++ = '0';
					*q++ = '0';
					*q++ = "0123456789abcdef"[*p >> 4 & 0xf];
					*q++ = "0123456789abcdef"[*p & 0xf];
				} else {
					*q++ = *p;
				}
			}
		} else if (ch_bytes == 4) {
			if (r_isprint (ch)) {
				// Assumes buf is UTF8-encoded
				for (i = 0; i < ch_bytes; i++) {
					*q++ = *(p + i);
				}
			} else {
				RRune high, low;
				ch -= 0x10000;
				high = 0xd800 + (ch >> 10 & 0x3ff);
				low = 0xdc00 + (ch & 0x3ff);
				*q++ = '\\';
				*q++ = 'u';
				for (i = 2; i >= 0; i -= 2) {
					*q++ = "0123456789abcdef"[high >> 4 * (i + 1) & 0xf];
					*q++ = "0123456789abcdef"[high >> 4 * i & 0xf];
				}
				*q++ = '\\';
				*q++ = 'u';
				for (i = 2; i >= 0; i -= 2) {
					*q++ = "0123456789abcdef"[low >> 4 * (i + 1) & 0xf];
					*q++ = "0123456789abcdef"[low >> 4 * i & 0xf];
				}
			}
		} else if (ch_bytes > 1) {
			if (r_isprint (ch)) {
				// Assumes buf is UTF8-encoded
				for (i = 0; i < ch_bytes; i++) {
					*q++ = *(p + i);
				}
			} else {
				*q++ = '\\';
				*q++ = 'u';
				for (i = 2; i >= 0; i -= 2) {
					*q++ = "0123456789abcdef"[ch >> 4 * (i + 1) & 0xf];
					*q++ = "0123456789abcdef"[ch >> 4 * i & 0xf];
				}
			}
		} else { // ch_bytes == 0
			// Outside JSON spec, but apparently no better
			// alternative if need to reconstruct the original string
			*q++ = '\\';
			*q++ = 'x';
			*q++ = "0123456789abcdef"[*p >> 4 & 0xf];
			*q++ = "0123456789abcdef"[*p & 0xf];
			ch_bytes = 1;
		}
		p += ch_bytes;
	}
	*q = '\0';
	return new_buf;
}

Project: radare2
File: test_str.c

bool test_r_str_escape_sh(void) {
	char *escaped = r_str_escape_sh ("Hello, \"World\"");
	mu_assert_streq (escaped, "Hello, \\\"World\\\"", "escaped \"double quotes\"");
	free (escaped);
	escaped = r_str_escape_sh ("Hello, \\World\\");
	mu_assert_streq (escaped, "Hello, \\\\World\\\\", "escaped backspace");
	free (escaped);
#if __UNIX__
	escaped = r_str_escape_sh ("Hello, $(World)");
	mu_assert_streq (escaped, "Hello, \\$(World)", "escaped $(command)");
	free (escaped);
	escaped = r_str_escape_sh ("Hello, `World`");
	mu_assert_streq (escaped, "Hello, \\`World\\`", "escaped `command`");
	free (escaped);
#endif
	mu_end;
}

Project: radare2
File: socket.c

R_API int r_socket_gets(RSocket *s, char *buf,	int size) {
	int i = 0;
	int ret = 0;

	if (s->fd == R_INVALID_SOCKET) {
		return -1;
	}
	while (i < size) {
		ret = r_socket_read (s, (ut8 *)buf + i, 1);
		if (ret == 0) {
			if (i > 0) {
				return i;
			}
			return -1;
		}
		if (ret < 0) {
			r_socket_close (s);
			return i == 0? -1: i;
		}
		if (buf[i] == '\r' || buf[i] == '\n') {
			buf[i] = 0;
			break;
		}
		i += ret;
	}
	buf[i] = '\0';
	return i;
}

Project: radare2
File: str.c

R_API char *r_str_word_get_first(const char *text) {
	for (; *text && IS_SEPARATOR (*text); text++) {
		;
	}
	return strdup (text);
}

Project: radare2
File: socket.c

R_API char *r_socket_to_string(RSocket *s) {
	return NULL;
}

Project: radare2
File: str.c

R_API int r_str_bits(char *strout, const ut8 *buf, int len, const char *bitz) {
	int i, j, idx;
	if (bitz) {
		for (i = j = 0; i<len && (!bitz||bitz[i]); i++) {
			if (i > 0 && (i % 8) == 0) {
				buf++;
			}
			if (*buf & (1 << (i % 8))) {
				strout[j++] = toupper ((const ut8)bitz[i]);
			}
		}
	} else {
		for (i = j = 0; i < len; i++) {
			idx = (i / 8);
			int bit = 7 - (i % 8);
			strout[j++] = (buf[idx] & (1 << bit))? '1' : '0';
		}
	}
	strout[j] = 0;
	return j;
}

Project: radare2
File: str.c

R_API bool r_str_isnumber(const char *str) {
	if (!str || !*str) {
		return false;
	}
	bool isnum = IS_DIGIT (*str) || *str == '-';
	while (isnum && *++str) {
		if (!IS_DIGIT (*str)) {
			isnum = false;
		}
	}
	return isnum;
}

Project: radare2
File: str.c

R_API int r_str_delta(char *p, char a, char b) {
	char *_a = strchr (p, a);
	char *_b = strchr (p, b);
	return (!_a || !_b)? 0 : (_a - _b);
}

Project: radare2
File: socket.c

R_API bool r_socket_is_connected(RSocket *s) {
#if __WINDOWS__
	char buf[2];
	r_socket_block_time (s, 0, 0, 0);
#ifdef _MSC_VER
	int ret = recv (s->fd, (char*)&buf, 1, MSG_PEEK);
#else
	ssize_t ret = recv (s->fd, (char*)&buf, 1, MSG_PEEK);
#endif
	r_socket_block_time (s, 1, 0, 0);
	return ret == 1;
#else
	int error = 0;
	socklen_t len = sizeof (error);
	int ret = getsockopt (s->fd, SOL_SOCKET, SO_ERROR, &error, &len);
	if (ret != 0) {
		perror ("getsockopt");
		return false;
	}
	if (error != 0) {
		return false;
	}
	return true;
#endif
}

Project: radare2
File: socket.c

R_API int r_socket_port_by_name(const char *name) {
	return -1;
}

Project: radare2
File: str.c

R_API const char *r_str_rchr(const char *base, const char *p, int ch) {
	r_return_val_if_fail (base, NULL);
	if (!p) {
		p = base + strlen (base);
	}
	for (; p >= base; p--) {
		if (ch == *p) {
			break;
		}
	}
	return (p >= base) ? p: NULL;
}

Project: radare2
File: str.c

R_API int r_str_replace_char(char *s, int a, int b) {
	return r_str_replace_ch (s, a, b, true);
}

Project: radare2
File: socket.c

R_API int r_socket_read_block(RSocket *s, ut8 *buf, int len) {
	int ret = 0;
	for (ret = 0; ret < len; ) {
		int r = r_socket_read (s, buf + ret, len - ret);
		if (r == -1) {
#if HAVE_LIB_SSL
			if (SSL_get_error (s->sfd, r) == SSL_ERROR_WANT_READ) {
				if (r_socket_ready (s, 1, 0) == 1) {
					continue;
				}
			}
#endif
			return -1;
		}
		if (r < 1) {
			break;
		}
		ret += r;
	}
	return ret;
}

Project: radare2
File: socket.c

R_API int r_socket_write(RSocket *s, void *buf, int len) {
	D { eprintf ("WRITE "); int i; ut8 *b = buf; for (i = 0; i<len; i++) { eprintf ("%02x ", b[i]); } eprintf ("\n"); }
	int ret, delta = 0;
#if __UNIX__
	r_sys_signal (SIGPIPE, SIG_IGN);
#endif
	for (;;) {
		int b = 1500; //65536; // Use MTU 1500?
		if (b > len) {
			b = len;
		}
#if HAVE_LIB_SSL
		if (s->is_ssl) {
			if (s->bio) {
				ret = BIO_write (s->bio, buf+delta, b);
			} else {
				ret = SSL_write (s->sfd, buf + delta, b);
			}
		} else
#endif
		{
			ret = send (s->fd, (char *)buf+delta, b, 0);
		}
		//if (ret == 0) return -1;
		if (ret < 1) {
			break;
		}
		if (ret == len) {
			return len;
		}
		delta += ret;
		len -= ret;
	}
	return (ret == -1)? -1 : delta;
}

Project: radare2
File: str.c

R_API char *r_str_between(const char *cmt, const char *prefix, const char *suffix) {
	char *c0, *c1;
	if (!cmt || !prefix || !suffix || !*cmt) {
		return NULL;
	}
	c0 = strstr (cmt, prefix);
	if (c0) {
		c1 = strstr (c0 + strlen (prefix), suffix);
		if (c1) {
			return r_str_ndup (c0 + strlen (prefix), (c1 - c0 - strlen (prefix)));
		}
	}
	return NULL;
}

Project: radare2
File: sys.c

R_API bool r_sys_arch_match(const char *archstr, const char *arch) {
	char *ptr;
	if (!archstr || !arch || !*archstr || !*arch) {
		return true;
	}
	if (!strcmp (archstr, "*") || !strcmp (archstr, "any")) {
		return true;
	}
	if (!strcmp (archstr, arch)) {
		return true;
	}
	if ((ptr = strstr (archstr, arch))) {
		char p = ptr[strlen (arch)];
		if (!p || p==',') {
			return true;
		}
	}
	return false;
}

Project: radare2
File: str.c

R_API char *r_str_prepend(char *ptr, const char *string) {
	int slen, plen;
	if (!ptr) {
		return strdup (string);
	}
	plen = strlen (ptr);
	slen = strlen (string);
	ptr = realloc (ptr, slen + plen + 1);
	if (!ptr) {
		return NULL;
	}
	memmove (ptr + slen, ptr, plen + 1);
	memmove (ptr, string, slen);
	return ptr;
}

Project: radare2
File: str.c

R_API const char *r_str_rstr(const char *base, const char *p) {
	char *s = strdup (base);
	char *k = strdup (p);
	r_str_reverse (s);
	r_str_reverse (k);
	char *q = strstr (s, k);
	const char *r = NULL;
	if (q) {
		r = base + strlen (base) - (q - s) - strlen (p);
	}
	free (s);
	free (k);
	return r;
}

Project: radare2
File: str.c

R_API int r_str_utf16_to_utf8(ut8 *dst, int len_dst, const ut8 *src, int len_src, int little_endian) {
	ut8 *outstart = dst;
	ut8 *outend = dst + len_dst;
	ut16 *in = (ut16*)src;
	ut16 *inend;
	ut32 c, d, inlen;
	ut8 *tmp;
	int bits;

	if ((len_src % 2) == 1) {
		len_src--;
	}
	inlen = len_src / 2;
	inend = in + inlen;
	while ((in < inend) && (dst - outstart + 5 < len_dst)) {
		if (little_endian) {
			c = *in++;
		} else {
			tmp = (ut8*) in;
			c = *tmp++;
			if (!c && !*tmp) {
				break;
			}
			c = c | (((ut32)*tmp) << 8);
			in++;
		}
		if ((c & 0xFC00) == 0xD800) {    /* surrogates */
			if (in >= inend) {           /* (in > inend) shouldn't happens */
				break;
			}
			if (little_endian) {
				d = *in++;
			} else {
				tmp = (ut8*) in;
				d = *tmp++;
				d = d | (((ut32)*tmp) << 8);
				in++;
			}
			if ((d & 0xFC00) == 0xDC00) {
				c &= 0x03FF;
				c <<= 10;
				c |= d & 0x03FF;
				c += 0x10000;
			} else {
				return -2;
			}
		}

		/* assertion: c is a single UTF-4 value */
		if (dst >= outend) {
			break;
		}
		if (c < 0x80) {
			*dst++ =  c; bits= -6;
		} else if (c < 0x800) {
			*dst++ = ((c >> 6) & 0x1F) | 0xC0;
			bits =  0;
		} else if (c < 0x10000) {
			*dst++ = ((c >> 12) & 0x0F) | 0xE0;
			bits =  6;
		} else {
			*dst++ = ((c >> 18) & 0x07) | 0xF0;
			bits = 12;
		}

		for (; bits >= 0; bits -= 6) {
			if (dst >= outend) {
				break;
			}
			*dst++ = ((c >> bits) & 0x3F) | 0x80;
		}
	}
	len_dst = dst - outstart;
	return len_dst;
}

Project: radare2
File: sys.c

R_API int r_sys_truncate(const char *file, int sz) {
#if __WINDOWS__
	int fd = r_sandbox_open (file, O_RDWR, 0644);
	if (fd == -1) {
		return false;
	}
#ifdef _MSC_VER
	int r = _chsize (fd, sz);
#else
	int r = ftruncate (fd, sz);
#endif
	if (r != 0) {
		eprintf ("Could not resize '%s' file\n", file);
		close (fd);
		return false;
	}
	close (fd);
	return true;
#else
	if (r_sandbox_enable (0)) {
		return false;
	}
	return truncate (file, sz) == 0;
#endif
}

Project: radare2
File: str.c

R_API char *r_str_nextword(char *s, char ch) {
	char *p = strchr (s, ch);
	if (!p) {
		return NULL;
	}
	*p++ = 0;
	return p;
}

Project: radare2
File: socket.c

R_API int r_socket_ready(RSocket *s, int secs, int usecs) {
	fd_set rfds;
	struct timeval tv = {secs, usecs};
	if (s->fd == R_INVALID_SOCKET) {
		return -1;
	}
	FD_ZERO (&rfds);
	FD_SET (s->fd, &rfds);
	return select (s->fd + 1, &rfds, NULL, NULL, &tv);
}

Project: radare2
File: str.c

R_API char *r_str_ansi_crop(const char *str, ut32 x, ut32 y, ut32 x2, ut32 y2) {
	char *r, *r_end, *ret;
	const char *s, *s_start;
	size_t r_len, str_len = 0, nr_of_lines = 0;
	ut32 ch = 0, cw = 0;
	if (x2 <= x || y2 <= y || !str) {
		return strdup ("");
	}
	s = s_start = str;
	while (*s) {
		str_len++;
		if (*s == '\n') {
			nr_of_lines++;
		}
		s++;
	}
	r_len = str_len + nr_of_lines * strlen (Color_RESET) + 1;
	r = ret = malloc (r_len);
	if (!r) {
		return NULL;
	}
	r_end = r + r_len;
	while (*str) {
		/* crop height */
		if (ch >= y2) {
			r--;
			break;
		}
		if (*str == '\n') {
			if (ch >= y && ch < y2) {
				const char *reset = Color_RESET "\n";
				if (strlen (reset) < (r_end - r)) {
					const int reset_length = strlen (reset);
					memcpy (r, reset, reset_length + 1);
					r += reset_length;
				}
			}
			str++;
			ch++;
			cw = 0;
		} else {
			if (ch >= y && ch < y2) {
				if ((*str & 0xc0) == 0x80) {
					if (cw > x) {
						*r++ = *str++;
					} else {
						str++;
					}
					continue;
				}
				if (r_str_char_fullwidth (str, str_len - (str - s_start))) {
					cw++;
					if (cw == x) {
						*r++ = ' ';
						str++;
						continue;
					}
				}
				if (*str == 0x1b && *(str + 1) == '[') {
					const char *ptr = str;
					if ((r_end - r) > 2) {
						/* copy 0x1b and [ */
						*r++ = *str++;
						*r++ = *str++;
						for (ptr = str; *ptr && *ptr != 'J' && *ptr != 'm' && *ptr != 'H'; ptr++) {
							*r++ = *ptr;
						}
						*r++ = *ptr++;
					}
					str = ptr;
					continue;
				} else if (cw >= x && cw < x2) {
					*r++ = *str;
				}
			}
			/* skip until newline */
			if (cw >= x2) {
				while (*str && *str != '\n') {
					str++;
				}
			} else {
				str++;
			}
			cw++;
		}
	}
	*r = 0;
	return ret;
}

Project: radare2
File: sys.c

R_API int r_sys_sigaction(int *sig, void (*handler) (int)) {
	struct sigaction sigact = { };
	int ret, i;

	if (!sig) {
		return -EINVAL;
	}

	sigact.sa_handler = handler;
	sigemptyset (&sigact.sa_mask);

	for (i = 0; sig[i] != 0; i++) {
		sigaddset (&sigact.sa_mask, sig[i]);
	}

	for (i = 0; sig[i] != 0; i++) {
		ret = sigaction (sig[i], &sigact, NULL);
		if (ret) {
			eprintf ("Failed to set signal handler for signal '%d': %s\n", sig[i], strerror(errno));
			return ret;
		}
	}

	return 0;
}

Project: radare2
File: str.c

R_API int r_str_bounds(const char *_str, int *h) {
	const char *str, *ptr;
	int W = 0, H = 0;
	int cw = 0;

	if (_str) {
		ptr = str = _str;
		while (*str) {
			if (*str == '\n') {
				H++;
				cw = r_str_ansi_nlen (ptr, (size_t)(str - ptr));
				if (cw > W) {
					W = cw;
				}
				cw = 0;
				ptr = str + 1;
			}
			str++;
			cw++;
		}
		if (*str == '\n') {// skip last newline
			H--;
		}
		if (h) {
			*h = H;
		}
	}
	return W;
}

Project: radare2
File: socket.c

R_API int r_socket_close_fd(RSocket *s) {
#ifdef _MSC_VER
	return s->fd != INVALID_SOCKET ? closesocket (s->fd) : false;
#else
	return s->fd != -1 ? close (s->fd) : false;
#endif
}

Project: radare2
File: sys.c

R_API bool r_is_heap (void *p) {
	void *q = malloc (8);
	ut64 mask = UT64_MAX;
	ut64 addr = (ut64)(size_t)q;
	addr >>= 16;
	addr <<= 16;
	mask >>= 16;
	mask <<= 16;
	free (q);
	return (((ut64)(size_t)p) == mask);
}

Project: radare2
File: pdb_downloader.c

void deinit_pdb_downloader(SPDBDownloader *pd) {
	R_FREE (pd->opt->dbg_file);
	R_FREE (pd->opt->guid);
	R_FREE (pd->opt->symbol_server);
	R_FREE (pd->opt->user_agent);
	R_FREE (pd->opt->symbol_store_path);
	R_FREE (pd->opt);
	pd->download = 0;
}

Project: radare2
File: sys.c

R_API void r_sys_set_environ (char **e) {
	env = e;
}

Project: radare2
File: test_str.c

bool test_r_str_bool(void) {
	const char* one = r_str_bool(1);
	const char* zero = r_str_bool(0);
	const char* fifty = r_str_bool(50);
	const char* negative = r_str_bool(-1);
	mu_assert_streq (one, "true", "one");
	mu_assert_streq (zero, "false", "zero");
	mu_assert_streq (fifty, "true", "large positive value");
	mu_assert_streq (negative, "true", "negative number");
	mu_end;
}

Project: radare2
File: str.c

R_API int r_str_path_unescape(char *path) {
	int i;

	for (i = 0; path[i]; i++) {
		if (path[i] != '\\') {
			continue;
		}
		if (path[i + 1] == ' ') {
			path[i] = ' ';
			memmove (path + i + 1, path + i + 2, strlen (path + i + 2) + 1);
		}
	}

	return i;
}

Project: radare2
File: str.c

R_API int r_str_ncasecmp(const char *s1, const char *s2, size_t n) {
#ifdef _MSC_VER
	return _strnicmp (s1, s2, n);
#else
	return strncasecmp (s1, s2, n);
#endif
}

Project: radare2
File: str.c

R_API const char *r_str_lastbut(const char *s, char ch, const char *but) {
	int idx, _b = 0;
	ut8 *b = (ut8*)&_b;
	const char *isbut, *p, *lp = NULL;
	const int bsz = sizeof (_b) * 8;
	if (!but) {
		return r_str_lchr (s, ch);
	}
	if (strlen (but) >= bsz) {
		eprintf ("r_str_lastbut: but string too long\n");
		return NULL;
	}
	for (p = s; *p; p++) {
		isbut = strchr (but, *p);
		if (isbut) {
			idx = (int)(size_t)(isbut - but);
			_b = R_BIT_TOGGLE (b, idx);
			continue;
		}
		if (*p == ch && !_b) {
			lp = p;
		}
	}
	return lp;
}

Project: radare2
File: str.c

R_API ut64 r_str_bits_from_string(const char *buf, const char *bitz) {
	ut64 out = 0LL;
	/* return the numeric value associated to a string (rflags) */
	for (; *buf; buf++) {
		char *ch = strchr (bitz, toupper ((const unsigned char)*buf));
		if (!ch) {
			ch = strchr (bitz, tolower ((const unsigned char)*buf));
		}
		if (ch) {
			int bit = (int)(size_t)(ch - bitz);
			out |= (ut64)(1LL << bit);
		} else {
			return UT64_MAX;
		}
	}
	return out;
}

Project: radare2
File: pdb_downloader.c

static bool is_valid_guid(const char *guid) {
	if (!guid) {
		return false;
	}
	size_t i;
	for (i = 0; guid[i]; i++) {
		if (!isxdigit (guid[i])) {
			return false;
		}
	}
	return i >= 33; // len of GUID and age
}

Project: radare2
File: sys.c

R_API const char *r_sys_arch_str(int arch) {
	int i;
	for (i = 0; arch_bit_array[i].name; i++) {
		if (arch & arch_bit_array[i].bit) {
			return arch_bit_array[i].name;
		}
	}
	return "none";
}

Project: radare2
File: sys.c

R_API int r_sys_cmdbg (const char *str) {
#if __UNIX__
	int ret, pid = r_sys_fork ();
	if (pid == -1) {
		return -1;
	}
	if (pid) {
		return pid;
	}
	ret = r_sandbox_system (str, 0);
	eprintf ("{exit: %d, pid: %d, cmd: \"%s\"}", ret, pid, str);
	exit (0);
	return -1;
#else
#ifdef _MSC_VER
#pragma message ("r_sys_cmdbg is not implemented for this platform")
#else
#warning r_sys_cmdbg is not implemented for this platform
#endif
	return -1;
#endif
}

Project: radare2
File: str.c

R_API char* r_str_wc_to_mb_l(const wchar_t *buf, int len) {
	char *res_buf = NULL;
	bool fail = true;
	size_t sz;

	if (!buf || len <= 0) {
		return NULL;
	}
	sz = wcstombs (NULL, buf, len);
	if (sz == (size_t)-1) {
		goto err_r_str_wc_to_mb;
	}
	res_buf = (char *)calloc (1, (sz + 1) * sizeof (char));
	if (!res_buf) {
		goto err_r_str_wc_to_mb;
	}
	sz = wcstombs (res_buf, buf, sz + 1);
	if (sz == (size_t)-1) {
		goto err_r_str_wc_to_mb;
	}
	fail = false;
err_r_str_wc_to_mb:
	if (fail) {
		R_FREE (res_buf);
	}
	return res_buf;
}

Project: radare2
File: str.c

R_API void r_str_stripLine(char *str, const char *key) {
	size_t i, j, klen, slen, off;
	const char *ptr;

	if (!str || !key) {
		return;
	}
	klen = strlen (key);
	slen = strlen (str);

	for (i = 0; i < slen; ) {
		ptr = (char*) r_mem_mem ((ut8*) str + i, slen - i, (ut8*) "\n", 1);
		if (!ptr) {
			ptr = (char*) r_mem_mem ((ut8*) str + i, slen - i, (ut8*) key, klen);
			if (ptr) {
				str[i] = '\0';
				break;
			}
			break;
		}

		off = (size_t) (ptr - (str + i)) + 1;

		ptr = (char*) r_mem_mem ((ut8*) str + i, off, (ut8*) key, klen);
		if (ptr) {
			for (j = i; j < slen - off + 1; j++) {
				str[j] = str[j + off];
			}
			slen -= off;
		} else {
			i += off;
		}
	}
}

Project: radare2
File: str.c

R_API char *r_str_escape_utf32be(const char *buf, int buf_size, bool show_asciidot, bool esc_bslash) {
	return r_str_escape_utf (buf, buf_size, R_STRING_ENC_UTF32BE, show_asciidot, esc_bslash, false);
}

Project: radare2
File: str.c

R_API const char *r_str_rwx_i(int rwx) {
	if (rwx < 0 || rwx >= R_ARRAY_SIZE (rwxstr)) {
		rwx = 0;
	}
	return rwxstr[rwx % 24]; // 15 for srwx
}

Project: radare2
File: str.c

R_API int r_str_ansi_filter(char *str, char **out, int **cposs, int len) {
	int i, j, *cps;

	if (len == 0) {
		return 0;
	}
	if (len < 0) {
		len = strlen (str);
	}
	char *tmp = malloc (len + 1);
	if (!tmp) {
		return -1;
	}
	memcpy (tmp, str, len + 1);
	cps = calloc (len + 1, sizeof (int));
	if (!cps) {
		free (tmp);
		return -1;
	}

	for (i = j = 0; i < len; i++) {
		if (tmp[i] == 0x1b) {
			size_t chlen = __str_ansi_length (str + i);
			if (chlen > 1) {
				i += chlen;
				i--;
			}
		} else {
			str[j] = tmp[i];
			cps[j] = i;
			j++;
		}
	}
	str[j] = tmp[i];

	if (out) {
		*out = tmp;
	} else {
		free (tmp);
	}

	if (cposs) {
		*cposs = cps;
	} else {
		free (cps);
	}

	return j;
}

Project: radare2
File: str.c

R_API bool r_str_char_fullwidth (const char* s, size_t left) {
	size_t codepoint = r_str_utf8_codepoint (s, left);
	return (codepoint >= 0x1100 &&
		 (codepoint <= 0x115f ||                  /* Hangul Jamo init. consonants */
			  codepoint == 0x2329 || codepoint == 0x232a ||
		 (R_BETWEEN (0x2e80, codepoint, 0xa4cf)
			&& codepoint != 0x303f) ||        /* CJK ... Yi */
		 R_BETWEEN (0xac00, codepoint, 0xd7a3) || /* Hangul Syllables */
		 R_BETWEEN (0xf900, codepoint, 0xfaff) || /* CJK Compatibility Ideographs */
		 R_BETWEEN (0xfe10, codepoint, 0xfe19) || /* Vertical forms */
		 R_BETWEEN (0xfe30, codepoint, 0xfe6f) || /* CJK Compatibility Forms */
		 R_BETWEEN (0xff00, codepoint, 0xff60) || /* Fullwidth Forms */
		 R_BETWEEN (0xffe0, codepoint, 0xffe6) ||
		 R_BETWEEN (0x20000, codepoint, 0x2fffd) ||
		 R_BETWEEN (0x30000, codepoint, 0x3fffd)));

}

Project: radare2
File: str.c

R_API void r_str_ncpy(char *dst, const char *src, size_t n) {
	int i;

	// do not do anything if n is 0
	if (n == 0) {
		return;
	}

	n--;
	for (i = 0; src[i] && n > 0; i++, n--) {
		dst[i] = src[i];
	}
	dst[i] = 0;
}

Project: radare2
File: socket.c

R_API int r_socket_flush(RSocket *s) {
#if HAVE_LIB_SSL
	if (s->is_ssl && s->bio) {
		return BIO_flush (s->bio);
	}
#endif
	return true;
}

Project: radare2
File: disk.c

static inline int r_sys_mkdirp(char *dir) {
	int ret = 1;
	const char slash = DIRSEP;
	char *path = dir;
	char *ptr = path;
	if (*ptr == slash) {
		ptr++;
	}
#if __SDB_WINDOWS__
	char *p = strstr (ptr, ":\\");
	if (p) {
		ptr = p + 3;
	}
#endif
	while ((ptr = strchr (ptr, slash))) {
		*ptr = 0;
		if (!r_sys_mkdir (path) && r_sys_mkdir_failed ()) {
			eprintf ("r_sys_mkdirp: fail '%s' of '%s'\n", path, dir);
			*ptr = slash;
			return 0;
		}
		*ptr = slash;
		ptr++;
	}
	return ret;
}

Project: radare2
File: sys.c

R_API char *r_sys_getenv(const char *key) {
#if __WINDOWS__
	DWORD dwRet;
	LPTSTR envbuf = NULL, key_ = NULL, tmp_ptr;
	char *val = NULL;

	if (!key) {
		return NULL;
	}
	envbuf = (LPTSTR)malloc (sizeof (TCHAR) * TMP_BUFSIZE);
	if (!envbuf) {
		goto err_r_sys_get_env;
	}
	key_ = r_sys_conv_utf8_to_win (key);
	dwRet = GetEnvironmentVariable (key_, envbuf, TMP_BUFSIZE);
	if (dwRet == 0) {
		if (GetLastError () == ERROR_ENVVAR_NOT_FOUND) {
			goto err_r_sys_get_env;
		}
	} else if (TMP_BUFSIZE < dwRet) {
		tmp_ptr = (LPTSTR)realloc (envbuf, dwRet * sizeof (TCHAR));
		if (!tmp_ptr) {
			goto err_r_sys_get_env;
		}
		envbuf = tmp_ptr;
		dwRet = GetEnvironmentVariable (key_, envbuf, dwRet);
		if (!dwRet) {
			goto err_r_sys_get_env;
		}
	}
	val = r_sys_conv_win_to_utf8_l (envbuf, (int)dwRet);
err_r_sys_get_env:
	free (key_);
	free (envbuf);
	return val;
#else
	char *b;
	if (!key) {
		return NULL;
	}
	b = getenv (key);
	return b? strdup (b): NULL;
#endif
}

Project: radare2
File: sys.c

R_API int r_sys_fork() {
#if HAVE_FORK
#if __WINDOWS__
	return -1;
#else
	return fork ();
#endif
#else
	return -1;
#endif
}

Project: radare2
File: str.c

R_API ut32 r_str_hash(const char *s) {
	return (ut32) r_str_hash64 (s);
}

Project: radare2
File: str.c

R_API int r_str_word_set0(char *str) {
	int i, quote = 0;
	char *p;
	if (!str || !*str) {
		return 0;
	}
	for (i = 0; str[i] && str[i + 1]; i++) {
		if (i > 0 && str[i-1] == ' ' && str[i] == ' ') {
			int len = strlen (str + i);
			memmove (str + i, str + i + 1, len);
			i--;
		}
	}
	if (str[i] == ' ') {
		str[i] = 0;
	}
	for (i = 1, p = str; *p; p++) {
		if (*p == '\"') {
			if (quote) {
				quote = 0;
				*p = '\0';
				// FIX: i++;
				continue;
			} else {
				quote = 1;
				memmove (p, p + 1, strlen (p + 1) + 1);
			}
		}
		if (quote) {
			continue;
		}
		if (*p == ' ') {
			char *q = p - 1;
			if (p > str && (*q == '\\' || !*q)) {
				memmove (p, p + 1, strlen (p + 1) + 1);
				if (*q == '\\') {
					*q = ' ';
					continue;
				}
				p--;
			}
			i++;
			*p = '\0';
		} // s/ /\0/g
	}
	return i;
}

Project: radare2
File: sys.c

R_API int r_sys_arch_id(const char *arch) {
	int i;
	for (i = 0; arch_bit_array[i].name; i++) {
		if (!strcmp (arch, arch_bit_array[i].name)) {
			return arch_bit_array[i].bit;
		}
	}
	return 0;
}

Project: radare2
File: str.c

R_API int r_str_ccpy(char *dst, char *src, int ch) {
	int i;
	for (i = 0; src[i] && src[i] != ch; i++) {
		dst[i] = src[i];
	}
	dst[i] = '\0';
	return i;
}

Project: radare2
File: sys.c

R_API RSysInfo *r_sys_info(void) {
#if __UNIX__
	struct utsname un = {{0}};
	if (uname (&un) != -1) {
		RSysInfo *si = R_NEW0 (RSysInfo);
		if (si) {
			si->sysname  = strdup (un.sysname);
			si->nodename = strdup (un.nodename);
			si->release  = strdup (un.release);
			si->version  = strdup (un.version);
			si->machine  = strdup (un.machine);
			return si;
		}
	}
#elif __WINDOWS__
	HKEY key;
	DWORD type;
	DWORD size;
	DWORD major;
	DWORD minor;
	char tmp[256] = {0};
	RSysInfo *si = R_NEW0 (RSysInfo);
	if (!si) {
		return NULL;
	}
	
	if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0,
		KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
		r_sys_perror ("r_sys_info/RegOpenKeyExA");
		r_sys_info_free (si);
		return NULL;
	}

	size = sizeof (tmp);
	if (RegQueryValueExA (key, "ProductName", NULL, &type,
		(LPBYTE)&tmp, &size) != ERROR_SUCCESS
		|| type != REG_SZ) {
		goto beach;
	}
	si->sysname = strdup (tmp);

	size = sizeof (major);
	if (RegQueryValueExA (key, "CurrentMajorVersionNumber", NULL, &type,
		(LPBYTE)&major, &size) != ERROR_SUCCESS
		|| type != REG_DWORD) {
		goto beach;
	}
	size = sizeof (minor);
	if (RegQueryValueExA (key, "CurrentMinorVersionNumber", NULL, &type,
		(LPBYTE)&minor, &size) != ERROR_SUCCESS
		|| type != REG_DWORD) {
		goto beach;
	}

	size = sizeof (tmp);
	if (RegQueryValueExA (key, "CurrentBuild", NULL, &type,
		(LPBYTE)&tmp, &size) != ERROR_SUCCESS
		|| type != REG_SZ) {
		goto beach;
	}
	si->version = r_str_newf ("%d.%d.%s", major, minor, tmp);

	size = sizeof (tmp);
	if (RegQueryValueExA (key, "ReleaseId", NULL, &type,
		(LPBYTE)tmp, &size) != ERROR_SUCCESS
		|| type != REG_SZ) {
		goto beach;
	}
	si->release = strdup (tmp);
beach:
	RegCloseKey (key);
	return si;
#endif
	return NULL;
}

Project: radare2
File: sys.c

R_API bool r_sys_aslr(int val) {
	bool ret = true;
#if __linux__
	const char *rva = "/proc/sys/kernel/randomize_va_space";
	char buf[3] = {0};
	snprintf(buf, sizeof (buf), "%d\n", val != 0 ? 2 : 0);
	int fd = r_sandbox_open (rva, O_WRONLY, 0644);
	if (fd != -1) {
		if (r_sandbox_write (fd, (ut8 *)buf, sizeof (buf)) != sizeof (buf)) {
			eprintf ("Failed to set RVA\n");
			ret = false;
		}
		close (fd);
	}
#elif __FreeBSD__ && __FreeBSD_version >= 1300000
	size_t vlen = sizeof (val);
	if (sysctlbyname ("kern.elf32.aslr.enable", NULL, 0, &val, vlen) == -1) {
		eprintf ("Failed to set RVA 32 bits\n");
		return false;
	}

#if __LP64__
	if (sysctlbyname ("kern.elf64.aslr.enable", NULL, 0, &val, vlen) == -1) {
		eprintf ("Failed to set RVA 64 bits\n");
		ret = false;
	}
#endif
#endif
	return ret;
}

Project: radare2
File: str.c

R_API int r_str_replace_ch(char *s, char a, char b, bool global) {
	int ret = 0;
	char *o = s;
	if (!s || a == b) {
		return 0;
	}
	for (; *o; s++, o++) {
		if (*o == a) {
			ret++;
			if (b) {
				*s = b;
			} else {
				/* remove char */
				s--;
			}
			if (!global) {
				return 1;
			}
		} else {
			*s = *o;
		}
	}
	*s = 0;
	return ret;
}

Project: radare2
File: sys.c

R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, int *len, char **sterr) {
	char *mysterr = NULL;
	if (!sterr) {
		sterr = &mysterr;
	}
	char buffer[1024], *outputptr = NULL;
	char *inputptr = (char *)input;
	int pid, bytes = 0, status;
	int sh_in[2], sh_out[2], sh_err[2];

	if (len) {
		*len = 0;
	}
	if (pipe (sh_in)) {
		return false;
	}
	if (output) {
		if (pipe (sh_out)) {
			close (sh_in[0]);
			close (sh_in[1]);
			close (sh_out[0]);
			close (sh_out[1]);
			return false;
		}
	}
	if (pipe (sh_err)) {
		close (sh_in[0]);
		close (sh_in[1]);
		return false;
	}

	switch ((pid = r_sys_fork ())) {
	case -1:
		return false;
	case 0:
		dup2 (sh_in[0], 0);
		close (sh_in[0]);
		close (sh_in[1]);
		if (output) {
			dup2 (sh_out[1], 1);
			close (sh_out[0]);
			close (sh_out[1]);
		}
		if (sterr) {
			dup2 (sh_err[1], 2);
		} else {
			close (2);
		}
		close (sh_err[0]);
		close (sh_err[1]);
		exit (r_sandbox_system (cmd, 0));
	default:
		outputptr = strdup ("");
		if (!outputptr) {
			return false;
		}
		if (sterr) {
			*sterr = strdup ("");
			if (!*sterr) {
				free (outputptr);
				return false;
			}
		}
		if (output) {
			close (sh_out[1]);
		}
		close (sh_err[1]);
		close (sh_in[0]);
		if (!inputptr || !*inputptr) {
			close (sh_in[1]);
		}
		// we should handle broken pipes somehow better
		r_sys_signal (SIGPIPE, SIG_IGN);
		size_t err_len = 0, out_len = 0;
		for (;;) {
			fd_set rfds, wfds;
			int nfd;
			FD_ZERO (&rfds);
			FD_ZERO (&wfds);
			if (output) {
				FD_SET (sh_out[0], &rfds);
			}
			if (sterr) {
				FD_SET (sh_err[0], &rfds);
			}
			if (inputptr && *inputptr) {
				FD_SET (sh_in[1], &wfds);
			}
			memset (buffer, 0, sizeof (buffer));
			nfd = select (sh_err[0] + 1, &rfds, &wfds, NULL, NULL);
			if (nfd < 0) {
				break;
			}
			if (output && FD_ISSET (sh_out[0], &rfds)) {
				if ((bytes = read (sh_out[0], buffer, sizeof (buffer))) < 1) {
					break;
				}
				char *tmp = realloc (outputptr, out_len + bytes + 1);
				if (!tmp) {
					R_FREE (outputptr);
					break;
				}
				outputptr = tmp;
				memcpy (outputptr + out_len, buffer, bytes);
				out_len += bytes;
			} else if (FD_ISSET (sh_err[0], &rfds) && sterr) {
				if ((bytes = read (sh_err[0], buffer, sizeof (buffer))) < 1) {
					break;
				}
				char *tmp = realloc (*sterr, err_len + bytes + 1);
				if (!tmp) {
					R_FREE (*sterr);
					break;
				}
				*sterr = tmp;
				memcpy (*sterr + err_len, buffer, bytes);
				err_len += bytes;
			} else if (FD_ISSET (sh_in[1], &wfds) && inputptr && *inputptr) {
				int inputptr_len = strlen (inputptr);
				bytes = write (sh_in[1], inputptr, inputptr_len);
				if (bytes != inputptr_len) {
					break;
				}
				inputptr += bytes;
				if (!*inputptr) {
					close (sh_in[1]);
					/* If neither stdout nor stderr should be captured,
					 * abort now - nothing more to do for select(). */
					if (!output && !sterr) {
						break;
					}
				}
			}
		}
		if (output) {
			close (sh_out[0]);
		}
		close (sh_err[0]);
		close (sh_in[1]);
		waitpid (pid, &status, 0);
		bool ret = true;
		if (status) {
			// char *escmd = r_str_escape (cmd);
			// eprintf ("error code %d (%s): %s\n", WEXITSTATUS (status), escmd, *sterr);
			// eprintf ("(%s)\n", output);
			// eprintf ("%s: failed command '%s'\n", __func__, escmd);
			// free (escmd);
			ret = false;
		}

		if (len) {
			*len = out_len;
		}
		if (*sterr) {
			(*sterr)[err_len] = 0;
		}
		if (outputptr) {
			outputptr[out_len] = 0;
		}
		if (output) {
			*output = outputptr;
		} else {
			free (outputptr);
		}
		return ret;
	}
	return false;
}

Project: radare2
File: str.c

R_API char *r_str_newlen(const char *str, int len) {
	if (len < 1) {
		return NULL;
	}
	char *buf = malloc (len + 1);
	if (buf) {
		memcpy (buf, str, len);
		buf[len] = 0;
	}
	return buf;
}

Project: radare2
File: str.c

R_API const char *r_str_sep(const char *base, const char *sep) {
	int i;
	while (*base) {
		for (i = 0; sep[i]; i++) {
			if (*base == sep[i]) {
				return base;
			}
		}
		base++;
	}
	return NULL;
}

Project: radare2
File: test_str.c

bool test_r_str_str_xy(void) {
	char *canvas = "Hello World\n"
		"This World is World\n"
		"World is Hello\n";
	int x = 0, y = 0;
	const char *next = r_str_str_xy (canvas, "World", NULL, &x, &y);
	mu_assert_eq (x, 6, "x of first occurrence");
	mu_assert_eq (y, 0, "y of first occurrence");
	next = r_str_str_xy (canvas, "World", next, &x, &y);
	mu_assert_eq (x, 5, "x of second occurrence");
	mu_assert_eq (y, 1, "y of second occurrence");
	next = r_str_str_xy (canvas, "World", next, &x, &y);
	mu_assert_eq (x, 14, "x of third occurrence");
	mu_assert_eq (y, 1, "y of third occurrence");
	next = r_str_str_xy (canvas, "World", next, &x, &y);
	mu_assert_eq (x, 0, "x of fourth occurrence");
	mu_assert_eq (y, 2, "y of fourth occurrence");
	next = r_str_str_xy (canvas, "World", next, &x, &y);
	mu_assert_null (next, "no more occurences");
	mu_end;
}

Project: radare2
File: str.c

R_API void r_str_byte_escape(const char *p, char **dst, int dot_nl, bool default_dot, bool esc_bslash) {
	char *q = *dst;
	switch (*p) {
	case '\n':
		*q++ = '\\';
		*q++ = dot_nl ? 'l' : 'n';
		break;
	case '\r':
		*q++ = '\\';
		*q++ = 'r';
		break;
	case '\\':
		*q++ = '\\';
		if (esc_bslash) {
			*q++ = '\\';
		}
		break;
	case '\t':
		*q++ = '\\';
		*q++ = 't';
		break;
	case '"' :
		*q++ = '\\';
		*q++ = '"';
		break;
	case '\f':
		*q++ = '\\';
		*q++ = 'f';
		break;
	case '\b':
		*q++ = '\\';
		*q++ = 'b';
		break;
	case '\v':
		*q++ = '\\';
		*q++ = 'v';
		break;
	case '\a':
		*q++ = '\\';
		*q++ = 'a';
		break;
	default:
		/* Outside the ASCII printable range */
		if (!IS_PRINTABLE (*p)) {
			if (default_dot) {
				*q++ = '.';
			} else {
				*q++ = '\\';
				*q++ = 'x';
				*q++ = "0123456789abcdef"[*p >> 4 & 0xf];
				*q++ = "0123456789abcdef"[*p & 0xf];
			}
		} else {
			*q++ = *p;
		}
	}
	*dst = q;
}

Project: radare2
File: str.c

R_API bool r_str_glob(const char* str, const char *glob) {
        const char* cp = NULL, *mp = NULL;
        if (!glob || !strcmp (glob, "*")) {
                return true;
        }
        if (!strchr (glob, '*')) {
                if (*glob == '^') {
                        glob++;
                        while (*str) {
                                if (*glob != *str) {
                                        return false;
                                }
                                if (!*++glob) {
                                        return true;
                                }
                                str++;
                        }
                } else {
                        return strstr (str, glob) != NULL;
                }
        }
        if (*glob == '^') {
                glob++;
        }
        while (*str && (*glob != '*')) {
                if (*glob != *str) {
                        return false;
                }
                glob++;
                str++;
        }
        while (*str) {
                if (*glob == '*') {
                        if (!*++glob) {
                                return true;
                        }
                        mp = glob;
                        cp = str + 1;
                } else if (*glob == *str) {
                        glob++;
                        str++;
                } else {
                        glob = mp;
                        str = cp++;
                }
        }
        while (*glob == '*') {
                ++glob;
        }
        return (*glob == '\x00');
}

Project: radare2
File: str.c

R_API char *r_str_from_ut64(ut64 val) {
	int i = 0;
	char *v = (char *)&val;
	char *str = (char *)calloc(1, 9);
	if (!str) {
		return NULL;
	}
	while (i < 8 && *v) {
		str[i++] = *v++;
	}
	return str;
}

Project: radare2
File: str.c

R_API size_t r_str_utf8_charsize(const char *str) {
	r_return_val_if_fail (str, 0);
	size_t size = 0;
	size_t length = strlen (str);
	while (size < length && size < 5) {
		size++;
		if ((str[size] & 0xc0) != 0x80) {
			break;
		}
	}
	return size < 5 ? size : 0;
}

Project: radare2
File: pdb_downloader.c

void init_pdb_downloader(SPDBDownloaderOpt *opt, SPDBDownloader *pd) {
	pd->opt = R_NEW0 (SPDBDownloaderOpt);
	if (!pd->opt) {
		pd->download = 0;
		eprintf ("Cannot allocate memory for SPDBDownloaderOpt.\n");
		return;
	}
	pd->opt->dbg_file = strdup (opt->dbg_file);
	pd->opt->guid = strdup (opt->guid);
	pd->opt->symbol_server = strdup (opt->symbol_server);
	pd->opt->user_agent = strdup (opt->user_agent);
	pd->opt->symbol_store_path = strdup (opt->symbol_store_path);
	pd->opt->extract = opt->extract;
	pd->download = download;
}

Project: radare2
File: str.c

R_API char *r_str_escape(const char *buf) {
	return r_str_escape_ (buf, false, true, true, false, true);
}

Project: radare2
File: str.c

R_API int r_str_do_until_token(str_operation op, char *str, const char tok) {
	int ret;
	if (!str) {
		return -1;
	}
	if (!op) {
		for (ret = 0; (str[ret] != tok) && str[ret]; ret++) {
			//empty body
		}
	} else {
		for (ret = 0; (str[ret] != tok) && str[ret]; ret++) {
			op (str + ret);
		}
	}
	return ret;
}

Project: radare2
File: str.c

R_API wchar_t* r_str_mb_to_wc_l(const char *buf, int len) {
	wchar_t *res_buf = NULL;
	size_t sz;
	bool fail = true;

	if (!buf || len <= 0) {
		return NULL;
	}
	sz = mbstowcs (NULL, buf, len);
	if (sz == (size_t)-1) {
		goto err_r_str_mb_to_wc;
	}
	res_buf = (wchar_t *)calloc (1, (sz + 1) * sizeof (wchar_t));
	if (!res_buf) {
		goto err_r_str_mb_to_wc;
	}
	sz = mbstowcs (res_buf, buf, sz + 1);
	if (sz == (size_t)-1) {
		goto err_r_str_mb_to_wc;
	}
	fail = false;
err_r_str_mb_to_wc:
	if (fail) {
		R_FREE (res_buf);
	}
	return res_buf;
}

Project: radare2
File: str.c

R_API char *r_str_escape_utf32le(const char *buf, int buf_size, bool show_asciidot, bool esc_bslash) {
	return r_str_escape_utf (buf, buf_size, R_STRING_ENC_UTF32LE, show_asciidot, esc_bslash, false);
}

Project: radare2
File: sys.c

R_API char *r_sys_getdir(void) {
#if __WINDOWS__
	return _getcwd (NULL, 0);
#else
	return getcwd (NULL, 0);
#endif
}

Project: radare2
File: test_str.c

bool test_r_str_rwx(void) {
	int rwx = r_str_rwx ("rwx");
	int rw =  r_str_rwx ("rw-");
	int rx = r_str_rwx ("rx");
	int none = r_str_rwx ("---");
	int number = r_str_rwx ("999");
	int rx_number = r_str_rwx ("5");
	int rwx_number = r_str_rwx ("7");
	mu_assert_eq (rwx, 7, "rwx");
	mu_assert_eq (rw, 6, "rw");
	mu_assert_eq (rx, 5, "rx");
	mu_assert_eq (none, 0, "no permissions");
	mu_assert_eq (number, 0, "large input number string");
	mu_assert_eq (rx_number, 5, "rx number");
	mu_assert_eq (rwx_number, 7, "rwx number");
	mu_end;
}

Project: radare2
File: str.c

R_API int r_str_split(char *str, char ch) {
	int i;
	char *p;
	if (!str || !*str) {
		return 0;
	}
	/* TODO: sync with r1 code */
	for (i = 1, p = str; *p; p++) {
		if (*p == ch) {
			i++;
			*p = '\0';
		} // s/ /\0/g
	}
	return i;
}

Project: radare2
File: sys.c

R_API char *r_sys_cmd_str(const char *cmd, const char *input, int *len) {
	char *output = NULL;
	if (r_sys_cmd_str_full (cmd, input, &output, len, NULL)) {
		return output;
	}
	free (output);
	return NULL;
}

Project: radare2
File: str.c

R_API size_t r_str_utf8_charsize_last(const char *str) {
	r_return_val_if_fail (str, 0);
	size_t len = strlen (str);
	return r_str_utf8_charsize_prev (str + len, len);
}

Project: radare2
File: socket.c

static bool __connect_unix(RSocket *s, const char *file) {
	struct sockaddr_un addr;
	int sock = socket (PF_UNIX, SOCK_STREAM, 0);
	if (sock < 0) {
		free (s);
		return false;
	}
	// TODO: set socket options
	addr.sun_family = AF_UNIX;
	strncpy (addr.sun_path, file, sizeof (addr.sun_path)-1);

	if (connect (sock, (struct sockaddr *)&addr, sizeof(addr))==-1) {
		close (sock);
		free (s);
		return false;
	}
	s->fd = sock;
	s->is_ssl = false;
	return true;
}

Project: radare2
File: str.c

R_API const char *r_sub_str_lchr(const char *str, int start, int end, char chr) {
	do {
		end--;
	} while (str[end] != chr && end >= start);
	return str[end] == chr ? &str[end] : NULL;
}

Project: radare2
File: str.c

R_API char *r_str_appendf(char *ptr, const char *fmt, ...) {
	va_list ap, ap2;

	va_start (ap, fmt);
	if (!strchr (fmt, '%')) {
		va_end (ap);
		return r_str_append (ptr, fmt);
	}
	va_copy (ap2, ap);
	int ret = vsnprintf (NULL, 0, fmt, ap2);
	ret++;
	char *p = calloc (1, ret);
	if (p) {
		(void)vsnprintf (p, ret, fmt, ap);
		ptr = r_str_append (ptr, p);
		free (p);
	}
	va_end (ap2);
	va_end (ap);
	return ptr;
}

Project: radare2
File: str.c

R_API size_t r_str_nlen(const char *str, int n) {
	size_t len = 0;
	if (str) {
		while (*str && n > 0) {
			len++;
			str++;
			n--;
		}
	}
	return len;
}

Project: radare2
File: str.c

R_API const char *r_str_word_get0(const char *str, int idx) {
	int i;
	const char *ptr = str;
	if (!ptr || idx < 0 /* prevent crashes with negative index */) {
		return (char *)nullstr;
	}
	for (i = 0; i != idx; i++) {
		ptr += strlen (ptr) + 1;
	}
	return ptr;
}

Project: radare2
File: str.c

R_API const char *r_str_get(const char *str) {
	return str? str: nullstr_c;
}

Project: radare2
File: str.c

R_API size_t r_str_utf8_codepoint(const char* s, size_t left) {
	if ((*s & 0x80) != 0x80) {
		return 0;
	} else if ((*s & 0xe0) == 0xc0 && left >= 1) {
		return ((*s & 0x1f) << 6) + (*(s + 1) & 0x3f);
	} else if ((*s & 0xf0) == 0xe0 && left >= 2) {
		return ((*s & 0xf) << 12) + ((*(s + 1) & 0x3f) << 6) + (*(s + 2) & 0x3f);
	} else if ((*s & 0xf8) == 0xf0 && left >= 3) {
		return ((*s & 0x7) << 18) + ((*(s + 1) & 0x3f) << 12) + ((*(s + 2) & 0x3f) << 6) + (*(s + 3) & 0x3f);
	}
	return 0;
}

Project: radare2
File: test_str.c

bool test_r_str_bits64(void) {
	char buf[65];
	(void)r_str_bits64 (buf, 0);
	mu_assert_streq (buf, "00000000", "binary of 0");
	(void)r_str_bits64 (buf, 1);
	mu_assert_streq (buf, "00000001", "binary of 1");
	(void)r_str_bits64 (buf, 2);
	mu_assert_streq (buf, "00000010", "binary of 2");
	mu_end;
}

Project: radare2
File: str.c

R_API size_t r_str_utf8_charsize_prev(const char *str, int prev_len) {
	r_return_val_if_fail (str, 0);
	int pos = 0;
	size_t size = 0, minsize = R_MIN (5, prev_len);
	while (size < minsize) {
		size++;
		if ((str[--pos] & 0xc0) != 0x80) {
			break;
		}
	}
	return size < 5 ? size : 0;
}

Project: radare2
File: str.c

R_API void r_str_case(char *str, bool up) {
	if (up) {
		char oc = 0;
		for (; *str; oc = *str++) {
			*str = (*str=='x' && oc=='0') ? 'x': toupper ((int)(ut8)*str);
		}
	} else {
		for (; *str; str++) {
			*str = tolower ((int)(ut8)*str);
		}
	}
}

Project: radare2
File: str.c

R_API bool r_str_is_bool(const char *val) {
	return r_str_is_true (val) || r_str_is_false (val);
}

Project: radare2
File: str.c

R_API bool r_str_is_true(const char *s) {
	return !r_str_casecmp ("yes", s)
		|| !r_str_casecmp ("on", s)
		|| !r_str_casecmp ("true", s)
		|| !r_str_casecmp ("1", s);
}

Project: radare2
File: sys.c

R_API int r_sys_usleep(int usecs) {
#if HAS_CLOCK_NANOSLEEP
	struct timespec rqtp;
	rqtp.tv_sec = usecs / 1000000;
	rqtp.tv_nsec = (usecs - (rqtp.tv_sec * 1000000)) * 1000;
	return clock_nanosleep (CLOCK_MONOTONIC, 0, &rqtp, NULL);
#elif __UNIX__
	return usleep (usecs);
#else
	// w32 api uses milliseconds
	usecs /= 1000;
	Sleep (usecs); // W32
	return 0;
#endif
}

Project: radare2
File: socket.c

R_API char *r_socket_to_string(RSocket *s) {
#if __WINDOWS__
	return r_str_newf ("fd%d", (int)(size_t)s->fd);
#elif __UNIX__
	char *str = NULL;
	struct sockaddr sa;
	socklen_t sl = sizeof (sa);
	memset (&sa, 0, sizeof (sa));
	if (!getpeername (s->fd, &sa, &sl)) {
		struct sockaddr_in *sain = (struct sockaddr_in*) &sa;
		ut8 *a = (ut8*) &(sain->sin_addr);
		if ((str = malloc (32))) {
			sprintf (str, "%d.%d.%d.%d:%d",
				a[0], a[1], a[2], a[3], ntohs (sain->sin_port));
		}
	} else {
		eprintf ("getperrname: failed\n"); //r_sys_perror ("getpeername");
	}
	return str;
#else
	return NULL;
#endif
}

Project: radare2
File: str.c

R_API size_t r_str_nlen_w(const char *str, int n) {
	size_t len = 0;
	if (str) {
		while (*str && n > 0) {
			len++;
			str++;
			if (!*str) {
				//handle wide strings
			 	//xx00yy00bb00
				if (n - 2 > 0) {
					if (str[2]) {
						break;
					}
				}
				str++;
			}
			n--;
		}
	}
	return len;
}

Project: radare2
File: socket_http.c

R_API char *r_socket_http_post(const char *url, const char *data, int *code, int *rlen) {
	RSocket *s;
	bool ssl = r_str_startswith (url, "https://");
	char *uri = strdup (url);
	if (!uri) {
		return NULL;
	}

	char *host = strstr (uri, "://");
	if (!host) {
		free (uri);
		printf ("Invalid URI");
		return NULL;
	}
	host += 3;
	char *port = strchr (host, ':');
	if (!port) {
		port = (ssl)? "443": "80";
	} else {
		*port++ = 0;
	}
	char *path = strchr (host, '/');
	if (!path) {
		path = "";
	} else {
		*path++ = 0;
	}
	s = r_socket_new (ssl);
	if (!s) {
		printf ("Cannot create socket\n");
		free (uri);
		return NULL;
	}
	if (!r_socket_connect_tcp (s, host, port, 0)) {
		eprintf ("Cannot connect to %s:%s\n", host, port);
		free (uri);
		return NULL;
	}
	/* Send */
	r_socket_printf (s,
			"POST /%s HTTP/1.0\r\n"
			"User-Agent: radare2 "R2_VERSION"\r\n"
			"Accept: */*\r\n"
			"Host: %s\r\n"
			"Content-Length: %i\r\n"
			"Content-Type: application/x-www-form-urlencoded\r\n"
			"\r\n", path, host, (int)strlen (data));
	free (uri);
	r_socket_write (s, (void *)data, strlen (data));
	return socket_http_answer (s, code, rlen, 0);
}

Project: radare2
File: sys.c

R_API int r_sys_cmdf(const char *fmt, ...) {
	int ret;
	char cmd[4096];
	va_list ap;
	va_start(ap, fmt);
	vsnprintf (cmd, sizeof (cmd), fmt, ap);
	ret = r_sys_cmd (cmd);
	va_end (ap);
	return ret;
}

Project: radare2
File: socket.c

R_API int r_socket_puts(RSocket *s, char *buf) {
	return -1;
}

Project: radare2
File: test_str.c

bool test_r_str_replace_char_once(void) {
	char* str = strdup ("hello world");
	(void) r_str_replace_char_once (str, 'l', 'x');
	mu_assert_streq (str, "hexlo world", "error, replace char once failed");
	free (str);
	mu_end;
}

Project: radare2
File: str.c

R_API const char *r_str_rsep(const char *base, const char *p, const char *sep) {
	int i;
	while (p >= base) {
		for (i = 0; sep[i]; i++) {
			if (*p == sep[i]) {
				return p;
			}
		}
		p--;
	}
	return NULL;
}

Project: radare2
File: socket.c

R_API int r_socket_puts(RSocket *s, char *buf) {
	return r_socket_write (s, buf, strlen (buf));
}

Project: radare2
File: str.c

R_API char* r_str_highlight(char *str, const char *word, const char *color, const char *color_reset) {
	if (!str || !*str) {
		return NULL;
	}
	ut32 i = 0, j = 0, to_copy;
	char *start = str;
	ut32 l_str = strlen (str);
	ut32 l_reset = strlen (color_reset);
	ut32 l_color = color? strlen (color): 0;
	if (!color) {
		return strdup (str);
	}
	if (!word || !*word) {
		return r_str_newf ("%s%s%s", color, str, color_reset);
	}
	ut32 l_word = strlen (word);
	// XXX don't use static buffers
	char o[1024] = {0};
	while (start && (start < str + l_str)) {
		int copied = 0;
		// find first letter
		start = strchr_skip_color_codes (str + i, *word);
		if (start) {
			to_copy = start - (str + i);
			if (to_copy + j + 1 > sizeof (o)) {
				// XXX. no limits
				break;
			}
			strncpy (o + j, str + i, to_copy);
			i += to_copy;
			j += to_copy;
			if (!strncmp_skip_color_codes (start, word, l_word)) {
				if (j + strlen (color) >= sizeof (o)) {
					// XXX. no limits
					break;
				}
				strcpy (o + j, color);
				j += l_color;
				if (j + l_word >= sizeof (o)) {
					// XXX. no limits
					break;
				}
				copied = strncpy_with_color_codes (o + j, str + i, l_word);
				i += copied;
				j += copied;
				if (j + strlen (color_reset) >= sizeof (o)) {
					// XXX. no limits
					break;
				}
				strcpy (o + j, color_reset);
				j += l_reset;
			} else {
				o[j++] = str[i++];
			}
		} else {
			if (j + strlen (str + i) >= sizeof (o)) {
				break;
			}
			strcpy (o + j, str + i);
			break;
		}
	}
	return strdup (o);
}

Project: radare2
File: test_str.c

bool test_r_str_lchr(void) {
	const char* test = "radare2";
	const char* out = r_str_lchr (test, 'r');
	mu_assert_streq (out, "re2", "pointer to last r in radare2");
	mu_end;
}

Project: radare2
File: test_str.c

bool test_r_str_sanitize_sdb_key(void) {
	char *s = r_str_sanitize_sdb_key("rada.re2<is>::Cool");
	mu_assert_streq (s, "rada_re2_is_::Cool", "sanitize");
	free (s);
	mu_end;
}

Project: radare2
File: str.c

R_API const char *r_str_firstbut(const char *s, char ch, const char *but) {
	int idx, _b = 0;
	ut8 *b = (ut8*)&_b;
	const char *isbut, *p;
	const int bsz = sizeof (_b) * 8;
	if (!but) {
		return strchr (s, ch);
	}
	if (strlen (but) >= bsz) {
		eprintf ("r_str_firstbut: but string too long\n");
		return NULL;
	}
	for (p = s; *p; p++) {
		isbut = strchr (but, *p);
		if (isbut) {
			idx = (int)(size_t)(isbut - but);
			_b = R_BIT_TOGGLE (b, idx);
			continue;
		}
		if (*p == ch && !_b) {
			return p;
		}
	}
	return NULL;
}

Project: radare2
File: str.c

R_API int r_str_write(int fd, const char *b) {
	return write (fd, b, strlen (b));
}

Project: radare2
File: str.c

R_API bool r_str_range_in(const char *r, ut64 addr) {
	const char *p = r;
	ut64 min = UT64_MAX;
	ut64 max = 0;
	if (!r) {
		return false;
	}
	for (; *r; r++) {
		if (*r == ',') {
			if (max == 0) {
				if (addr == r_num_get (NULL, p)) {
					return true;
				}
			} else {
				if (addr >= min && addr <= r_num_get (NULL, p)) {
					return true;
				}
			}
			p = r + 1;
		}
		if (*r == '-') {
			if (p != r) {
				ut64 from = r_num_get (NULL, p);
				ut64 to = r_num_get (NULL, r + 1);
				if (addr >= from && addr <= to) {
					return true;
				}
			} else {
				fprintf (stderr, "Invalid range\n");
			}
			for (r++; *r && *r != ',' && *r != '-'; r++) {
				;
			}
			p = r;
		}
	}
	if (*p) {
		if (addr == r_num_get (NULL, p)) {
			return true;
		}
	}
	return false;
}

Project: radare2
File: test_str.c

bool test_r_str_trim(void) {
	//  1
	const char* one = r_str_trim_head_ro ("  hello  ");
	mu_assert_streq (one, "hello  ", "one");
	//  2
	char* two = strdup ("  hello  ");
	r_str_trim_head (two);
	mu_assert_streq (two, "hello  ", "two");
	r_str_trim (two);
	//  2
	mu_assert_streq (two, "hello", "three");
	free (two);
	mu_end;
}

Project: radare2
File: sys.c

R_API char *r_sys_pid_to_path(int pid) {
#if __WINDOWS__
	// TODO: add maximum path length support
	HANDLE processHandle;
	const DWORD maxlength = MAX_PATH;
	TCHAR filename[MAX_PATH];
	char *result = NULL;

	processHandle = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
	if (!processHandle) {
		eprintf ("r_sys_pid_to_path: Cannot open process.\n");
		return NULL;
	}
	DWORD length = GetModuleFileNameEx (processHandle, NULL, filename, maxlength);
	if (length == 0) {
		// Upon failure fallback to GetProcessImageFileName
		length = GetProcessImageFileName (processHandle, filename, maxlength);
		CloseHandle (processHandle);
		if (length == 0) {
			eprintf ("r_sys_pid_to_path: Error calling GetProcessImageFileName\n");
			return NULL;
		}
		// Convert NT path to win32 path
		char *name = r_sys_conv_win_to_utf8 (filename);
		if (!name) {
			eprintf ("r_sys_pid_to_path: Error converting to utf8\n");
			return NULL;
		}
		char *tmp = strchr (name + 1, '\\');
		if (!tmp) {
			free (name);
			eprintf ("r_sys_pid_to_path: Malformed NT path\n");
			return NULL;
		}
		tmp = strchr (tmp + 1, '\\');
		if (!tmp) {
			free (name);
			eprintf ("r_sys_pid_to_path: Malformed NT path\n");
			return NULL;
		}
		length = tmp - name;
		tmp = malloc (length + 1);
		if (!tmp) {
			free (name);
			eprintf ("r_sys_pid_to_path: Error allocating memory\n");
			return NULL;
		}
		strncpy (tmp, name, length);
		tmp[length] = '\0';
		TCHAR device[MAX_PATH];
		for (TCHAR drv[] = TEXT("A:"); drv[0] <= TEXT('Z'); drv[0]++) {
			if (QueryDosDevice (drv, device, maxlength) > 0) {
				char *dvc = r_sys_conv_win_to_utf8 (device);
				if (!dvc) {
					free (name);
					free (tmp);
					eprintf ("r_sys_pid_to_path: Error converting to utf8\n");
					return NULL;
				}
				if (!strcmp (tmp, dvc)) {
					free (tmp);
					free (dvc);
					char *d = r_sys_conv_win_to_utf8 (drv);
					if (!d) {
						free (name);
						eprintf ("r_sys_pid_to_path: Error converting to utf8\n");
						return NULL;
					}
					tmp = r_str_newf ("%s%s", d, &name[length]);
					free (d);
					if (!tmp) {
						free (name);
						eprintf ("r_sys_pid_to_path: Error calling r_str_newf\n");
						return NULL;
					}
					result = strdup (tmp);
					break;
				}
				free (dvc);
			}
		}
		free (name);
		free (tmp);
	} else {
		CloseHandle (processHandle);
		result = r_sys_conv_win_to_utf8 (filename);
	}
	return result;
#elif __APPLE__
#if __POWERPC__
#warning TODO getpidproc
	return NULL;
#else
	char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
	pathbuf[0] = 0;
	int ret = proc_pidpath (pid, pathbuf, sizeof (pathbuf));
	if (ret <= 0) {
		return NULL;
	}
	return strdup (pathbuf);
#endif
#else
	int ret;
#if __FreeBSD__
	char pathbuf[PATH_MAX];
	size_t pathbufl = sizeof (pathbuf);
	int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid};
	ret = sysctl (mib, 4, pathbuf, &pathbufl, NULL, 0);
	if (ret != 0) {
		return NULL;
	}
#else
	char buf[128], pathbuf[1024];
	snprintf (buf, sizeof (buf), "/proc/%d/exe", pid);
	ret = readlink (buf, pathbuf, sizeof (pathbuf)-1);
	if (ret < 1) {
		return NULL;
	}
	pathbuf[ret] = 0;
#endif
	return strdup (pathbuf);
#endif
}