str_util.c.svn-base
来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· SVN-BASE 代码 · 共 1,161 行 · 第 1/2 页
SVN-BASE
1,161 行
char *mem_to_hexstr(const unsigned char *buf, int len){ int i; char *tmp; /* 2 hex chars per byte, +1 for terminating 0 */ char *ret = (char*)malloc(len * 2 + 1); if (!ret) return NULL; tmp = ret; for (i = 0; i < len; i++) { char_to_hex(*buf++, tmp); tmp += 2; } *tmp = 0; return ret;}/* replace a string pointed by <dst> with a copy of <src> (i.e. free existing <dst>). Returns FALSE if failed to replace (due to out of memory) */BOOL str_dup_replace(char **dst, const char *src){ char *dup = (char*)strdup(src); if (!dup) return FALSE; free(*dst); *dst = dup; return TRUE;}/* Reverse of mem_to_hexstr. Convert a 0-terminatd hex-encoded string <s> to binary data pointed by <buf> of max sisze bufLen. Returns FALSE if size of <s> doesn't match <bufLen>. */BOOL hexstr_to_mem(const char *s, unsigned char *buf, int bufLen){ int i, c; for (i=0; i<bufLen; i++) { c = hex_str_decode_byte(&s); if (-1 == c) return FALSE; *buf++ = (unsigned char)c; } return *s == 0;}int str_contains(const char *str, char c){ const char *pos = str_find_char(str, c); if (!pos) return FALSE; return TRUE;}#define CHAR_URL_DONT_ENCODE "-_.!~*'()"int char_needs_url_encode(char c){ if ((c >= 'a') && (c <= 'z')) return FALSE; if ((c >= 'A') && (c <= 'Z')) return FALSE; if ((c >= '0') && (c <= '9')) return FALSE; if (str_contains(CHAR_URL_DONT_ENCODE, c)) return FALSE; return TRUE;}/* url-encode 'str'. Returns NULL in case of error. Caller needs to free() the result */char *str_url_encode(const char *str){ char * encoded; char * result; int res_len = 0; const char * tmp = str; /* calc the size of the string after url encoding */ while (*tmp) { if (char_needs_url_encode(*tmp)) res_len += 3; else ++res_len; tmp++; } if (0 == res_len) return NULL; encoded = (char*)malloc(res_len+1); if (!encoded) return NULL; result = encoded; tmp = str; while (*tmp) { if (char_needs_url_encode(*tmp)) { *encoded++ = '%'; char_to_hex(*tmp, encoded); encoded += 2; } else { if (' ' == *tmp) *encoded++ = '+'; else *encoded++ = *tmp; } tmp++; } *encoded = 0; return result;}char *str_escape(const char *txt){ /* TODO: */ return str_dup(txt);}char *str_printf(const char *format, ...){ char *result; va_list args; va_start(args, format); result = str_printf_args(format, args); va_end(args); return result;}char *str_printf_args(const char *format, va_list args){#ifdef _WIN32 char message[256]; char * buf; size_t bufCchSize; buf = &(message[0]); bufCchSize = sizeof(message);# ifndef DISABLE_STRSAFE for (;;) { /* TODO: this only works on windows with recent C library */ HRESULT hr = StringCchVPrintfA(buf, bufCchSize, format, args); if (S_OK == hr) break; if (STRSAFE_E_INSUFFICIENT_BUFFER != hr) { /* any error other than buffer not big enough: a) should not happen b) means we give up */ assert(FALSE); goto Error; } /* we have to make the buffer bigger. The algorithm used to calculate the new size is arbitrary (aka. educated guess) */ if (buf != &(message[0])) free(buf); if (bufCchSize < 4*1024) bufCchSize += bufCchSize; else bufCchSize += 1024; buf = (char *)malloc(bufCchSize*sizeof(char)); if (NULL == buf) goto Error; }# else /* strsafe is disabled */ { int len = vsnprintf(buf, bufCchSize, format, args); if(len >= bufCchSize) { bufCchSize = len + 1; buf = (char *)malloc(bufCchSize*sizeof(char)); if (NULL == buf) goto Error; len = vsnprintf(buf, bufCchSize, format, args); } if(len < 0) goto Error; }# endif /* free the buffer if it was dynamically allocated */ if (buf == &(message[0])) return str_dup(buf); return buf;Error: if (buf != &(message[0])) free((void*)buf); return NULL;#else char* buf; int len = vasprintf(&buf, format, args); return buf;#endif}#ifdef _WIN32void win32_dbg_out(const char *format, ...) { char buf[4096]; char * p = buf; int written; va_list args; va_start(args, format); written = _vsnprintf(p,sizeof(buf), format, args);/* printf(buf); fflush(stdout); */ OutputDebugStringA(buf); va_end(args);}void win32_dbg_out_hex(const char *dsc, const unsigned char *data, int dataLen){ unsigned char buf[64+1]; unsigned char * curPos; int bufCharsLeft; if (dsc) win32_dbg_out(dsc); /* a bit dangerous if contains formatting codes */ if (!data) return; bufCharsLeft = sizeof(buf)-1; curPos = buf; while (dataLen > 0) { if (bufCharsLeft <= 1) { *curPos = 0; win32_dbg_out((char*)buf); bufCharsLeft = sizeof(buf)-1; curPos = buf; } char_to_hex(*data, curPos); curPos += 2; bufCharsLeft -= 2; --dataLen; ++data; } if (curPos != buf) { *curPos = 0; win32_dbg_out(buf); } win32_dbg_out("\n");}#endif/* If the string at <*strp> starts with string at <expect>, skip <*strp> past it and return TRUE; otherwise return FALSE. */int str_skip(const char **strp, const char *expect){ size_t len = str_len(expect); if (0 == strncmp(*strp, expect, len)) { *strp += len; return TRUE; } else { return FALSE; }}/* Copy the string from <*strp> into <dst> until <stop> is found, and point <*strp> at the end. Returns TRUE unless <dst_size> isn't big enough, in which case <*strp> is still updated, but FALE is returned and <dst> is truncated. If <delim> is not found, <*strp> will point to the end of the string and FALSE is returned. */intstr_copy_skip_until(const char **strp, char *dst, size_t dst_size, char stop){ const char *const str = *strp; size_t len = str_len(str); *strp = memchr(str, stop, len); if (NULL==*strp) { *strp = str+len; return FALSE; } else return str_copyn(dst, dst_size, str, *strp - str);}/* Given a pointer to a string in '*txt', skip past whitespace in the string and put the result in '*txt' */void str_skip_ws(char **txtInOut){ char *cur; if (!txtInOut) return; cur = *txtInOut; if (!cur) return; while (char_is_ws(*cur)) { ++cur; } *txtInOut = cur;}char *str_parse_quoted(char **txt){ char * strStart; char * strCopy; char * cur; char * dst; char c; size_t len; assert(txt); if (!txt) return NULL; strStart = *txt; assert(strStart); if (!strStart) return NULL; assert('"' == *strStart); /* TODO: rewrite as 2-phase logic so that counting and copying are always in sync */ ++strStart; cur = strStart; len = 0; for (;;) { c = *cur; if ((0 == c) || ('"' == c)) break; if ('\\' == c) { /* TODO: should I un-escape more than '"' ? I used to un-escape '\' as well, but it wasn't right and files with UNC path like "\\foo\file.pdf" failed to load */ if ('"' == cur[1]) { ++cur; c = *cur; } } ++cur; ++len; } strCopy = (char*)malloc(len+1); if (!strCopy) return NULL; cur = strStart; dst = strCopy; for (;;) { c = *cur; if (0 == c) break; if ('"' == c) { ++cur; break; } if ('\\' == c) { /* TODO: should I un-escape more than '"' ? I used to un-escape '\' as well, but it wasn't right and files with UNC path like "\\foo\file.pdf" failed to load */ if ('"' == cur[1]) { ++cur; c = *cur; } } *dst++ = c; ++cur; } *dst = 0; *txt = cur; return strCopy;}char *str_parse_non_quoted(char **txt){ char * cur; char * strStart; char * strCopy; char c; size_t strLen; strStart = *txt; assert(strStart); if (!strStart) return NULL; assert('"' != *strStart); cur = strStart; for (;;) { c = *cur; if (char_is_ws_or_zero(c)) break; ++cur; } strLen = cur - strStart; assert(strLen > 0); strCopy = str_dupn(strStart, strLen); *txt = cur; return strCopy;}/* 'txt' is path that can be: - escaped, in which case it starts with '"', ends with '"' and each '"' that is part of the name is escaped with '\' - unescaped, in which case it start with != '"' and ends with ' ' or eol (0) This function extracts escaped or unescaped path from 'txt'. Returns NULL in case of error. Caller needs to free() the result. */char *str_parse_possibly_quoted(char **txt){ char * cur; char * str_copy; if (!txt) return NULL; cur = *txt; if (!cur) return NULL; str_skip_ws(&cur); if (0 == *cur) return NULL; if ('"' == *cur) str_copy = str_parse_quoted(&cur); else str_copy = str_parse_non_quoted(&cur); *txt = cur; return str_copy;}BOOL str_to_double(const char *txt, double *resOut){ int res; assert(txt); if (!txt) return FALSE; res = sscanf(txt, "%lf", resOut); if (1 != res) return FALSE; return TRUE;}/* Return the number of digits needed to represents a given number in base 10 string representation.*/size_t digits_for_number(int64_t num){ size_t digits = 1; /* negative numbers need '-' in front of them */ if (num < 0) { ++digits; num = -num; } while (num >= 10) { ++digits; num = num / 10; } return digits;}void str_array_init(str_array *str_arr){ assert(str_arr); if (!str_arr) return; memzero(str_arr, sizeof(str_array));}void str_array_free(str_array *str_arr){ int i; assert(str_arr); if (!str_arr) return; for (i = 0; i < str_arr->items_count; i++) free(str_arr->items[i]); free(str_arr->items); str_array_init(str_arr);}void str_array_delete(str_array *str_arr){ assert(str_arr); if (!str_arr) return; str_array_free(str_arr); free((void*)str_arr);}str_item *str_array_get(str_array *str_arr, int index){ assert(str_arr); if (!str_arr) return NULL; assert(index >= 0); assert(index < str_arr->items_count); if ((index < 0) || (index >= str_arr->items_count)) return NULL; return str_arr->items[index];}int str_array_get_count(str_array *str_arr){ assert(str_arr); if (!str_arr) return 0; return str_arr->items_count;}/* Set one string at position 'index' in 'str_arr'. Space for the item must already be allocated. */str_item *str_array_set(str_array *str_arr, int index, const char *str){ str_item * new_item; size_t str_len_cch; assert(str_arr); if (!str_arr) return NULL; if (index >= str_arr->items_count) return NULL; str_len_cch = str_len(str); new_item = (str_item*)malloc(sizeof(str_item) + str_len_cch*sizeof(char)); if (!new_item) return NULL; str_copy(new_item->str, str_len_cch+1, str); if (str_arr->items[index]) free(str_arr->items[index]); str_arr->items[index] = new_item; return new_item;}#define STR_ARR_GROW_VALUE 32/* make a generic array alloc */str_item *str_array_add(str_array *str_arr, const char *str){ str_item ** tmp; str_item * new_item; void * data; int n; if (str_arr->items_count >= str_arr->items_allocated) { /* increase memory for items if necessary */ n = str_arr->items_allocated + STR_ARR_GROW_VALUE; tmp = (str_item**)realloc(str_arr->items, n * sizeof(str_item *)); if (!tmp) return NULL; str_arr->items = tmp; data = &(str_arr->items[str_arr->items_count]); memzero(data, STR_ARR_GROW_VALUE * sizeof(str_item *)); str_arr->items_allocated = n; } str_arr->items_count++; new_item = str_array_set(str_arr, str_arr->items_count - 1, str); if (!new_item) --str_arr->items_count; return new_item;}int str_array_exists_no_case(str_array *str_arr, const char *str){ int count, i; str_item * item; char * item_str; if (!str_arr || !str) return FALSE; count = str_arr->items_count; for (i = 0; i < count; i++) { item = str_arr->items[i]; item_str = item->str; if (str_ieq(str, item_str)) return TRUE; } return FALSE;}str_item *str_array_add_no_dups(str_array *str_arr, const char *str){ if (str_array_exists_no_case(str_arr, str)) return NULL; return str_array_add(str_arr, str);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?