/* radare - LGPL - Copyright 2007-2015 - 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; if (!s || !*s) return; 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; if (a==b) return 0; 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; if (a==b) return 0; 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 ((const unsigned char)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; } /** * function: r_str_bits_from_num * */ R_API ut64 r_str_bits_from_string(const char *buf, const char *bitz) { ut64 out = 0LL; /* return the numberic 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; } /* 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, 'm') ? 16 : 0; 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[24] = { [0] = "----", [1] = "---x", [2] = "--w-", [3] = "--wx", [4] = "-r--", [5] = "-r-x", [6] = "-rw-", [7] = "-rwx", [8] = "----", [9] = "---x", [10] = "--w-", [11] = "--wx", [12] = "-r--", [13] = "-r-x", [14] = "-rw-", [15] = "-rwx", [16] = "m---", [17] = "m--x", [18] = "m-w-", [19] = "m-wx", [20] = "mr--", [21] = "mr-x", [22] = "mrw-", [23] = "mrwx", /* ... */ }; return rwxstr[rwx % 24]; // 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 ((unsigned char)*str); } else for (; *str; str++) *str = tolower ((unsigned char)*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 + 2); 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) return NULL; if (!p) p = base + strlen (base); 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) { va_end (ap2); va_end (ap); return NULL; } ret2 = vsnprintf (p, ret + 1, fmt, ap2); if (ret2 < 1 || ret2 > ret + 1) { free (p); va_end (ap2); va_end (ap); return NULL; } fmt = r_str_new (p); free (p); } else { fmt = r_str_new (string); } va_end (ap2); va_end (ap); return (char*)fmt; } // TODO: rename to r_str_trim_inplace() or something like that R_API char *r_str_chop(char *str) { int len; char *ptr; if (!str) return NULL; while (*str && iswhitechar (*str)) memmove (str, str + 1, strlen (str + 1) + 1); len = strlen (str); if (len > 0) { for (ptr = str + len-1; ptr != str; ptr--) { if (!iswhitechar (*ptr)) break; *ptr = '\0'; } } return str; } R_API const char *r_str_trim_const(const char *str) { if (str) for (; *str && iswhitechar (*str); str++); return str; } /* remove spaces from the head of the string. * the string is changed in place */ R_API char *r_str_trim_head(char *str) { char *p; if (!str) return NULL; for (p = str; *p && iswhitechar (*p); p++) ; /* Take the trailing null into account */ memmove (str, p, strlen (p) + 1); return str; } R_API char *r_str_trim_tail(char *str) { int length; if (!str) return NULL; length = strlen (str); if (!length) return str; while (length--) { if (iswhitechar (str[length])) str[length] = '\0'; else break; } return str; } R_API char *r_str_trim_head_tail(char *str) { return r_str_trim_tail (r_str_trim_head (str)); } R_API char *r_str_trim(char *str) { int i; char *ptr; if (!str) 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); strncpy (out, ptr, len); out[len] = 0; return out; } // TODO: deprecate? R_API char *r_str_dup(char *ptr, const char *string) { int len; 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; } R_API char *r_str_concatlen(char *ptr, const char *string, int slen) { char *ret, *msg = r_str_newlen (string, slen); ret = r_str_concat (ptr, msg); free (msg); return ret; } /* * 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 NULL; if (!string && ptr) return ptr; if (string && !ptr) return 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) { va_end (ap); 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; } /* replace the key in str with val. * * str - input string * clean - input string cleaned of ANSI chars * thunk - array of integers that map each char of the clean string into the * position in the str string * clen - number of elements in thunk * key - string to find in the clean string * val - string that replaces key in the str string * g - if true, replace all occurences of key * * It returns a pointer to the modified string */ 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; ) { bias = 0; 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"); free (str); free (scnd); str = NULL; 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; } R_API char *r_str_replace_in(char *str, ut32 sz, const char *key, const char *val, int g) { char *heaped; if (!str || !key || !val) return NULL; heaped = r_str_replace (strdup (str), key, val, g); strncpy (str, heaped, sz); free (heaped); 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]=='\\') { buf[i] = '\\'; 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; } } } /* Internal function. dot_nl specifies wheter to convert \n into the * graphiz-compatible newline \l */ static char *r_str_escape_ (const char *buf, const int dot_nl) { char *new_buf, *q; const char *p; if (!buf) return NULL; /* Worst case scenario, we convert every byte */ new_buf = malloc (1 + (strlen (buf) * 4)); if (!new_buf) return NULL; p = buf; q = new_buf; while (*p) { switch (*p) { case '\n': *q++ = '\\'; *q++ = dot_nl? 'l': 'n'; break; case '\r': *q++ = '\\'; *q++ = 'r'; break; case '\\': *q++ = '\\'; *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 0x1b: // ESC 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; break; default: /* Outside the ASCII printable range */ if (*p < ' ' && *p > 0x7E) { *q++ = '\\'; *q++ = 'x'; *q++ = '0'+((*p)>>4); *q++ = '0'+((*p)&0xf); } else { *q++ = *p; } } p++; } out: *q = '\0'; return new_buf; } R_API char *r_str_escape (const char *buf) { return r_str_escape_ (buf, R_FALSE); } R_API char *r_str_escape_dot (const char *buf) { return r_str_escape_ (buf, R_TRUE); } /* 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 } i++; } return len-sub; } /* suposed to chop a string with ansi controls to * max length of n. */ R_API int r_str_ansi_chop(char *str, int str_len, int n) { char ch, ch2; int back = 0, i = 0, len = 0; if (!str) { return 0; } /* simple case - no need to cut */ if (str_len<0) { str_len = strlen (str); } if (n >= str_len) { str[str_len] = 0; return str_len; } while ((i < str_len) && str[i] && len < n && n > 0) { 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; (i < str_len) && str[i] && str[i]!='J' && str[i]!='m' && str[i]!='H'; i++); } } else if ((str[i] & 0xc0) != 0x80) len++; i++; back = i; /* index in the original array */ } str[back] = 0; return back; } // TODO: support wide char strings R_API int r_str_nlen(const char *str, int n) { int len = 0; if (str) { //while (IS_PRINTABLE (*str) && n>0) { while (*str && n>0) { len++; str++; n--; } } return len; } R_API int r_str_is_printable(const char *str) { while (*str) { if (!IS_PRINTABLE (*str)) return 0; str++; } return 1; } // Length in chars of a wide string (find better name?) R_API int r_wstr_clen (const char *s) { int len = 0; if (*s++ == 0) return 0; while (*s++ || *s++) len++; return len+1; } 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; } /* * filter out ansi CSI shit in-place!. * str - input string, * out - if not NULL write a pointer to the original string there, * cposs - if not NULL write a pointer to thunk array there * (*cposs)[i] is the offset of the out[i] in str * len - lenght of str * * it returns the number of normal characters found in str */ R_API int r_str_ansi_filter(char *str, char **out, int **cposs, int len) { int i, j, *cps; char *tmp; if (len < 1) len = strlen (str); tmp = malloc (len + 1); if (!tmp) return -1; memcpy (tmp, str, len + 1); cps = malloc(len * sizeof(int)); for (i = j = 0; i < len; i++) { if ((i + 1) < len && tmp[i] == 0x1b && tmp[i + 1] == '[') { for (i += 2; i < len && str[i] != 'J' && str[i] != 'm' && str[i] != 'H'; 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; } R_API char *r_str_ansi_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 (*str == 0x1b && str + 1 && *(str + 1) == '[') { const char *ptr; /* copy 0x1b and [ */ *r++ = *str++; *r++ = *str++; for (ptr = str; *ptr && *ptr != 'J' && *ptr != 'm' && *ptr != 'H'; ++ptr) *r++ = *ptr; *r++ = *ptr++; str = ptr; } 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; } R_API void r_str_filter_zeroline(char *str, int len) { int i; for (i=0; i= argv_len) { argv_len *= 2; argv = realloc (argv, argv_len * sizeof (char *)); } arg_begin = args_current; } while (cmdline[cmdline_current++] != '\0'); argv[argc] = NULL; argv = realloc (argv, (argc+1) * sizeof (char *)); if (_argc) *_argc = argc; free (args); return argv; } R_API void r_str_argv_free(char **argv) { // TODO: free the internal food or just the first element // free (argv[0]); // MEMORY LEAK int argc = 0; while (argv[argc]) free (argv[argc++]); free (argv); } 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); 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_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", 0xff & ((ut8)*s)); *d++ = ch[0]; *d++ = ch[1]; } } *d = 0; return realloc (od, strlen (od)+1); // FIT } 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 >= 0x20) && (*s <= 126)) { *d++ = *s; } else { *d++ = '\\'; *d++ = '\\'; *d++ = 'u'; *d++ = '0'; *d++ = '0'; sprintf (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; } // 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; arg = orig; for (idx=0; argW) W = cw; cw = 0; } str++; cw++; } if (*str == '\n') // skip last newline H--; if (h) *h = H; return W; } #else R_API int r_str_bounds(const char *_str, int *h) { char *ostr, *str, *ptr; int W = 0, H = 0; int cw = 0; if (_str) { ptr = str = ostr = strdup (_str); while (*str) { if (*str=='\n') { H++; *str = 0; cw = (size_t)(str-ptr); cw = r_str_ansi_len (ptr); if (cw>W) W = cw; *str = '\n'; cw = 0; ptr = str; } str++; cw++; } if (*str == '\n') // skip last newline H--; if (h) *h = H; free (ostr); } return W; } #endif /* crop a string like it is in a rectangle with the upper-left corner at (x, y) * coordinates and the bottom-right corner at (x2, y2) coordinates. The result * is a newly allocated string, that should be deallocated by the user */ 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; } 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; } 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++) { } } else { for (ret = 0; (str[ret] != tok) && str[ret]; ret++) { op (str+ret); } } return ret; } 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