/* radare - LGPL - Copyright 2007-2014 - pancake */ #include "r_types.h" #include "r_util.h" #include #include #include #include /* stable code */ static const char *nullstr = ""; static const char *nullstr_c = "(null)"; // TODO: simplify this horrible loop R_API void r_str_chop_path (char *s) { char *src, *dst, *p; int i = 0; dst = src = s+1; while (*src) { if (*(src-1) == '/' && *src == '.' && *(src+1) == '.') { if (*(src+2) == '/' || *(src+2) == '\0') { p = dst-1; while (s != p) { if (*p == '/') { if (i) { dst = p+1; i = 0; break; } i = 1; } p--; } if (s == p && *p == '/') dst = p+1; src = src+2; } else { *dst = *src; dst++; } } else if (*src == '/' && *(src+1) == '.' && (*(src+2) == '/' || *(src+2) == '\0')) { src++; } else if (*src != '/' || *(src-1) != '/') { *dst = *src; dst++; } src++; } if (dst>s+1 && *(dst-1) == '/') *(dst-1) = 0; else *dst = 0; } R_API int r_str_replace_char_once (char *s, int a, int b) { int ret = 0; char *o = s; for (; *o; s++, o++) { if (*o==a) { if (b) { *s = b; ret++; continue; } o++; } *s = *o; } *s = 0; return ret; } // Spagetti.. must unify and support 'g', 'i' ... R_API int r_str_replace_char (char *s, int a, int b) { int ret = 0; char *o = s; for (; *o; s++, o++) { if (*o==a) { ret++; if (b) { *s = b; } else { /* remove char */ s--; } } else *s = *o; } *s = 0; return ret; } // TODO: do not use toupper.. must support modes to also append lowercase chars like in r1 // TODO: this functions needs some stabilization R_API int r_str_bits (char *strout, const ut8 *buf, int len, const char *bitz) { int i, j; if (bitz) { for (i=j=0; i0 && (i%8)==0) buf++; if (*buf&(1<<(i%8))) strout[j++] = toupper (bitz[i]); } } else { for (i=j=0; i0 && (i%8)==0) buf++; strout[j++] = (*buf&(1<<(7-(i%8))))?'1':'0'; } } strout[j] = 0; return j; } /* int c; ret = hex2int(&c, 'c'); */ static int hex2int (ut8 *val, ut8 c) { if ('0' <= c && c <= '9') *val = (ut8)(*val) * 16 + ( c - '0'); else if (c >= 'A' && c <= 'F') *val = (ut8)(*val) * 16 + ( c - 'A' + 10); else if (c >= 'a' && c <= 'f') *val = (ut8)(*val) * 16 + ( c - 'a' + 10); else return 1; return 0; } 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=i; j--, k++) { // INVERSE for (k=0,j=i; j j=%d (%c) (%02x)\n", j, str[j], str[j]); if (str[j]=='1') ret|=1< %02x\n", ret); out[n++] = ret; if (n==outlen) return n; } return n; } R_API int r_str_rwx(const char *str) { int ret = atoi (str); if (!ret) { ret |= strchr (str, 'r')?4:0; ret |= strchr (str, 'w')?2:0; ret |= strchr (str, 'x')?1:0; } return ret; } R_API const char *r_str_rwx_i(int rwx) { static const char *rwxstr[16] = { [0] = "---", [1] = "--x", [2] = "-w-", [3] = "-wx", [4] = "r--", [5] = "r-x", [6] = "rw-", [7] = "rwx", /* ... */ }; return rwxstr[rwx&7]; // 15 for srwx } R_API const char *r_str_bool(int b) { return b? "true": "false"; } R_API void r_str_case(char *str, int up) { if (up) { char oc = 0; for (; *str; oc = *str++) *str = (*str=='x' && oc=='0') ? 'x': toupper (*str); } else for (; *str; str++) *str = tolower (*str); } R_API char *r_str_home(const char *str) { char *dst, *home = r_sys_getenv (R_SYS_HOME); size_t length; if (home == NULL) return NULL; length = strlen (home) + 1; if (str) length += strlen (R_SYS_DIR) + strlen (str); dst = (char *)malloc (length); if (dst == NULL) goto fail; strcpy (dst, home); if (str) { strcat (dst, R_SYS_DIR); strcat (dst, str); } fail: free (home); return dst; } 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; } R_API ut32 r_str_hash (const char *s) { return (ut32) r_str_hash64 (s); } 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); } 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; } 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 (str[i]==' ' && str[i+1]==' ') { int len = strlen (str+i+1)+1; memmove (str+i, str+i+1, len); } } 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=='\\') { memmove (q, p, strlen (p)+1); continue; } i++; *p='\0'; } // s/ /\0/g } return i; } 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); 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); 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; } R_API const char *r_str_word_get0(const char *str, int idx) { int i; const char *ptr = str; if (ptr == NULL) return (char *)nullstr; for (i=0; *ptr && i != idx; i++) ptr += strlen (ptr) + 1; return ptr; } 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; } R_API int r_str_word_count(const char *string) { const char *text, *tmp; int word; for (text = tmp = string; *text && isseparator (*text); text++); for (word = 0; *text; word++) { for (;*text && !isseparator (*text); text++); for (tmp = text; *text && isseparator (*text); text++); } return word; } R_API char *r_str_ichr(char *str, char chr) { while (*str==chr) str++; return str; } // find last char 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; } R_API const char *r_str_rchr(const char *base, const char *p, int ch) { if (!base||!p) return NULL; for (; p>base; p--) if (ch == *p) break; return p; } R_API int r_str_nchr(const char *str, char chr) { int n; for (n = 0; *str; str++) if (*str==chr) n++; return n; } R_API int r_str_nstr(char *from, char *to, int size) { int i; for (i=0; i=sizeof (string)) { p = malloc (ret+2); if (!p) return NULL; ret2 = vsnprintf (p, ret+1, fmt, ap2); if (ret2<1 || ret2>ret+1) { free (p); return NULL; } fmt = r_str_new (p); free (p); } else fmt = r_str_new (string); va_end (ap); return (char*)fmt; } R_API char *r_str_chop(char *str) { int len; char *ptr; if (str == NULL) return NULL; while (*str && iswhitechar (*str)) str = str + 1; len = strlen (str); if (len>0) for (ptr = str+len-1; ptr!=str; ptr--) { if (iswhitechar (*ptr)) *ptr = '\0'; else break; } return str; } R_API const char *r_str_trim_head(const char *str) { if (str) while (*str && iswhitechar (*str)) str++; return str; } R_API char *r_str_trim_tail(char *str) { char *ptr = str; if (str == NULL) return NULL; if (!*str) return str; ptr += strlen (str); for (ptr--; (ptr > str) && iswhitechar (*ptr); ptr--) *ptr = '\0'; return str; } R_API char *r_str_trim_head_tail(char *str) { return r_str_trim_tail ((char*)r_str_trim_head (str)); } R_API char *r_str_trim(char *str) { int i; char *ptr; if (str == NULL) return NULL; for (ptr=str, i=0;str[i]; i++) if (!iswhitechar (str[i])) *ptr++ = str[i]; *ptr='\0'; return str; } R_API void r_str_ncpy(char *dst, const char *src, int n) { int i; for (i=0; src[i] && n>0; i++, n--) dst[i] = IS_PRINTABLE (src[i])? src[i]: '.'; dst[i] = 0; } /* memccmp("foo.bar", "foo.cow, '.') == 0 */ R_API int 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 1; return 0; } R_API int r_str_cmp(const char *a, const char *b, int len) { if (a==b) return R_TRUE; for (;len--;) { if (*a=='\0'||*b=='\0'||*a!=*b) return R_TRUE; a++; b++; } return R_FALSE; } 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; } R_API char *r_str_word_get_first(const char *text) { char *ret; int len = 0; for (;*text && isseparator (*text); text++); /* strdup */ len = strlen (text); ret = (char *)malloc (len+1); if (ret == NULL) { eprintf ("Cannot allocate %d bytes.\n", len+1); exit (1); } strncpy (ret, text, len); ret[len]='\0'; return ret; } R_API const char *r_str_get(const char *str) { if (str == NULL) return nullstr_c; return str; } R_API char *r_str_ndup(const char *ptr, int len) { char *out = malloc (len+1); memcpy (out, ptr, len); out[len] = 0; return out; } // TODO: deprecate? R_API char *r_str_dup(char *ptr, const char *string) { int len; if (ptr) free (ptr); if (!string) return NULL; len = strlen (string)+1; ptr = malloc (len+1); memcpy (ptr, string, len); return ptr; } R_API void r_str_writef(int fd, const char *fmt, ...) { char *buf; va_list ap; va_start (ap, fmt); if ((buf = malloc (4096)) != NULL) { vsnprintf (buf, 4096, fmt, ap); r_str_write (fd, buf); free (buf); } va_end (ap); } R_API char *r_str_prefix(char *ptr, const char *string) { int slen, plen; if (ptr == NULL) return strdup (string); //plen = r_str_len_utf8 (ptr); //slen = r_str_len_utf8 (string); plen = strlen (ptr); slen = strlen (string); ptr = realloc (ptr, slen + plen + 1); if (ptr == NULL) return NULL; memmove (ptr+slen, ptr, plen+1); memmove (ptr, string, slen); return ptr; } /* * first argument must be allocated * return: the pointer ptr resized to string size. */ // TODO: use vararg here? R_API char *r_str_concat(char *ptr, const char *string) { int slen, plen; if (!string && ptr) return ptr; if (string && !ptr) return strdup (string); if (!ptr) ptr = strdup (string); plen = strlen (ptr); slen = strlen (string); ptr = realloc (ptr, slen + plen + 1); if (ptr == NULL) return NULL; memcpy (ptr+plen, string, slen+1); return ptr; } R_API char *r_str_concatf(char *ptr, const char *fmt, ...) { int ret; char string[4096]; va_list ap; va_start (ap, fmt); ret = vsnprintf (string, sizeof (string), fmt, ap); if (ret>=sizeof (string)) { char *p = malloc (ret+2); if (!p) return NULL; vsnprintf (p, ret+1, fmt, ap); ptr = r_str_concat (ptr, p); free (p); } else ptr = r_str_concat (ptr, string); va_end (ap); return ptr; } R_API char *r_str_concatch(char *x, char y) { char b[2] = {y, 0}; return r_str_concat (x,b); } // XXX: wtf must deprecate R_API void *r_str_free(void *ptr) { free (ptr); return NULL; } R_API char* r_str_replace(char *str, const char *key, const char *val, int g) { int off, i, klen, vlen, slen; char *newstr, *scnd, *p = str; if (!str || !key || !val) return NULL; klen = strlen (key); vlen = strlen (val); if (klen == vlen && !strcmp (key, val)) return str; slen = strlen (str); for (i = 0; i < slen; ) { p = (char *)r_mem_mem ( (const ut8*)str + i, slen - i, (const ut8*)key, klen); if (!p) break; off = (int)(size_t)(p-str); scnd = strdup (p+klen); slen += vlen - klen; // HACK: this 32 avoids overwrites wtf newstr = realloc (str, slen+klen+1); if (!newstr) { eprintf ("realloc fail\n"); free (str); free (scnd); str = NULL; break; } str = newstr; p = str+off; memcpy (p, val, vlen); memcpy (p+vlen, scnd, strlen (scnd)+1); i = off+vlen; free (scnd); if (!g) break; } return str; } R_API char *r_str_clean(char *str) { int len; char *ptr; if (str != NULL) { while (*str && iswhitechar (*str)) str++; if ((len = strlen (str)) > 0 ) for (ptr = str+len-1; ptr!=str; ptr = ptr - 1) { if (iswhitechar (*ptr)) *ptr = '\0'; else break; } } return str; } 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; if (buf[i+1]=='e') { buf[i] = 0x1b; memmove (buf+i+1, buf+i+2, strlen (buf+i+2)+1); } else if (buf[i+1]=='r') { buf[i] = 0x0d; memmove (buf+i+1, buf+i+2, strlen (buf+i+2)+1); } else if (buf[i+1]=='n') { buf[i] = 0x0a; memmove (buf+i+1, buf+i+2, strlen (buf+i+2)+1); } else if (buf[i+1]=='x') { err = ch2 = ch = 0; if (!buf[i+2] || !buf[i+3]) { eprintf ("Unexpected end of string.\n"); return 0; } err |= hex2int (&ch, buf[i+2]); err |= hex2int (&ch2, buf[i+3]); if (err) { eprintf ("Error: Non-hexadecimal chars in input.\n"); return 0; // -1? } buf[i] = (ch<<4)+ch2; memmove (buf+i+1, buf+i+4, strlen (buf+i+4)+1); } else { eprintf ("'\\x' expected.\n"); return 0; // -1? } } return i; } 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; } } } R_API char *r_str_escape(const char *buf) { char *ptr, *ret; int len; if (!buf) return NULL; len = strlen (buf); ptr = ret = malloc (1+len*2); if (ptr == NULL) return NULL; for (; *buf; buf++, ptr++) { if (*buf=='\n') { *ptr = '\\'; ptr++; *ptr = 'n'; } else if (*buf=='\t') { *ptr = '\\'; ptr++; *ptr = 't'; } else if (IS_PRINTABLE (*buf)) { *ptr = *buf; } else { ut8 ch = *buf; *ptr++ = '\\'; *ptr++ = '0'+(ch>>4); *ptr = '0'+(ch&0xf); } } *ptr = 0; r_str_sanitize (ret); return ret; } /* ansi helpers */ R_API int r_str_ansi_len(const char *str) { int ch, ch2, i=0, len = 0, sub = 0; while (str[i]) { ch = str[i]; ch2 = str[i+1]; if (ch == 0x1b) { if (ch2 == '\\') { i++; } else if (ch2 == ']') { if (!strncmp (str+2+5, "rgb:", 4)) i += 18; } else if (ch2 == '[') { for (++i; str[i]&&str[i]!='J'&& str[i]!='m'&&str[i]!='H';i++); } } else { len++; #if 0 int olen = strlen (str); int ulen = r_str_len_utf8 (str); if (olen != ulen) { len += (olen-ulen); } else len++; //sub -= (r_str_len_utf8char (str+i, 4))-2; #endif }//len++; i++; } return len-sub; } // TODO: support wide char strings R_API int r_str_nlen(const char *str, int n) { int len = 0; while (*str++ && n--) len++; return len; } R_API const char *r_str_ansi_chrn(const char *str, int n) { int len, i, li; for (li=i=len=0; str[i] && (n!=len); i++) { if (str[i]==0x1b && str[i+1]=='[') { for (++i;str[i]&&str[i]!='J'&&str[i]!='m'&&str[i]!='H';i++); } else { if ((str[i] & 0xc0) != 0x80) len++; //len++; li = i; } } return str+li; } R_API int r_str_ansi_filter(char *str, int len) { int i, j; char *tmp = malloc (len); if (!tmp) return -1; memcpy (tmp, str, len); for (i=j=0; i= bsz) { eprintf ("r_str_lastbut: but string too long\n"); return NULL; } for (p=s; *p; p++) { isbut = but? strchr (but, *p): NULL; if (isbut) { idx = (int)(size_t)(isbut-but); _b = R_BIT_CHK (b, idx)? R_BIT_UNSET (b, idx): R_BIT_SET (b, idx); continue; } if (*p == ch && !_b) lp = p; } return lp; } // Must be merged inside strlen R_API int r_str_len_utf8char (const char *s, int left) { int i = 1; while (s[i] && (!left || i= needle_len) { if (strncasecmp (a, b, needle_len) == 0) return (const char *) a; a++; hay_len--; } return NULL; } R_API int r_str_write (int fd, const char *b) { return write (fd, b, strlen (b)); } 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)); } // convert from html escaped sequence "foo%20bar" to "foo bar" // TODO: find better name.. unencode? decode R_API void r_str_uri_decode (char *s) { int n; char *d; for (d=s; *s; s++, d++) { #if 0 if (*s == '+') { *d = ' '; } else #endif if (*s == '%') { sscanf (s+1, "%02x", &n); *d = n; s+=2; } else *d = *s; } *d = 0; } 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++ = '%'; sprintf (ch, "%02x", (unsigned char)*s); *d++ = ch[0]; *d++ = ch[1]; } } *d = 0; return realloc (od, strlen (od)+1); // FIT } // TODO: merge print inside rutil /* hack from print */ R_API int r_print_format_length (const char *fmt) { int nargs, i, j, idx, times, endian; char *args, *bracket, tmp, last = 0; const char *arg = fmt; const char *argend = arg+strlen (fmt); char namefmt[8]; int viewflags = 0; nargs = endian = i = j = 0; while (*arg && iswhitechar (*arg)) arg++; /* get times */ times = atoi (arg); if (times > 0) while ((*arg>='0'&&*arg<='9')) arg++; bracket = strchr (arg,'{'); if (bracket) { char *end = strchr (arg,'}'); if (end == NULL) { eprintf ("No end bracket. Try pm {ecx}b @ esi\n"); return 0; } *end='\0'; times = r_num_math (NULL, bracket+1); arg = end + 1; } if (*arg=='\0') return 0; /* get args */ args = strchr (arg, ' '); if (args) { int l=0, maxl = 0; argend = args; args = strdup (args+1); nargs = r_str_word_set0 (args+1); if (nargs == 0) R_FREE (args); for (i=0; imaxl) maxl = len; } l++; snprintf (namefmt, sizeof (namefmt), "%%%ds : ", maxl); } /* go format */ i = 0; if (!times) times = 1; for (; times; times--) { // repeat N times const char * orig = arg; idx = 0; arg = orig; for (idx=0; arg