📄 util_str.c
字号:
/* Unix SMB/CIFS implementation. Samba utility functions Copyright (C) Andrew Tridgell 1992-2001 Copyright (C) Simo Sorce 2001-2002 Copyright (C) Martin Pool 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "includes.h"/** * @file * @brief String utilities. **//** * Get the next token from a string, return False if none found. * Handles double-quotes. * * Based on a routine by GJC@VILLAGE.COM. * Extensively modified by Andrew.Tridgell@anu.edu.au **/BOOL next_token(const char **ptr,char *buff, const char *sep, size_t bufsize){ char *s; char *pbuf; BOOL quoted; size_t len=1; if (!ptr) return(False); s = (char *)*ptr; /* default to simple separators */ if (!sep) sep = " \t\n\r"; /* find the first non sep char */ while (*s && strchr_m(sep,*s)) s++; /* nothing left? */ if (! *s) return(False); /* copy over the token */ pbuf = buff; for (quoted = False; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) { if ( *s == '\"' ) { quoted = !quoted; } else { len++; *pbuf++ = *s; } } *ptr = (*s) ? s+1 : s; *pbuf = 0; return(True);}/**This is like next_token but is not re-entrant and "remembers" the first parameter so you can pass NULL. This is useful for user interface codebut beware the fact that it is not re-entrant!**/static const char *last_ptr=NULL;BOOL next_token_nr(const char **ptr,char *buff, const char *sep, size_t bufsize){ BOOL ret; if (!ptr) ptr = &last_ptr; ret = next_token(ptr, buff, sep, bufsize); last_ptr = *ptr; return ret; }static uint16 tmpbuf[sizeof(pstring)];void set_first_token(char *ptr){ last_ptr = ptr;}/** Convert list of tokens to array; dependent on above routine. Uses last_ptr from above - bit of a hack.**/char **toktocliplist(int *ctok, const char *sep){ char *s=(char *)last_ptr; int ictok=0; char **ret, **iret; if (!sep) sep = " \t\n\r"; while(*s && strchr_m(sep,*s)) s++; /* nothing left? */ if (!*s) return(NULL); do { ictok++; while(*s && (!strchr_m(sep,*s))) s++; while(*s && strchr_m(sep,*s)) *s++=0; } while(*s); *ctok=ictok; s=(char *)last_ptr; if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1))) return NULL; while(ictok--) { *iret++=s; if (ictok > 0) { while(*s++) ; while(!*s) s++; } } ret[*ctok] = NULL; return ret;}/** * Case insensitive string compararison. * * iconv does not directly give us a way to compare strings in * arbitrary unix character sets -- all we can is convert and then * compare. This is expensive. * * As an optimization, we do a first pass that considers only the * prefix of the strings that is entirely 7-bit. Within this, we * check whether they have the same value. * * Hopefully this will often give the answer without needing to copy. * In particular it should speed comparisons to literal ascii strings * or comparisons of strings that are "obviously" different. * * If we find a non-ascii character we fall back to converting via * iconv. * * This should never be slower than convering the whole thing, and * often faster. * * A different optimization would be to compare for bitwise equality * in the binary encoding. (It would be possible thought hairy to do * both simultaneously.) But in that case if they turn out to be * different, we'd need to restart the whole thing. * * Even better is to implement strcasecmp for each encoding and use a * function pointer. **/int StrCaseCmp(const char *s, const char *t){ const char *ps, *pt; size_t size; smb_ucs2_t *buffer_s, *buffer_t; int ret; for (ps = s, pt = t; ; ps++, pt++) { char us, ut; if (!*ps && !*pt) return 0; /* both ended */ else if (!*ps) return -1; /* s is a prefix */ else if (!*pt) return +1; /* t is a prefix */ else if ((*ps & 0x80) || (*pt & 0x80)) /* not ascii anymore, do it the hard way from here on in */ break; us = toupper_ascii(*ps); ut = toupper_ascii(*pt); if (us == ut) continue; else if (us < ut) return -1; else if (us > ut) return +1; } size = push_ucs2_allocate(&buffer_s, ps); if (size == (size_t)-1) { return strcmp(ps, pt); /* Not quite the right answer, but finding the right one under this failure case is expensive, and it's pretty close */ } size = push_ucs2_allocate(&buffer_t, pt); if (size == (size_t)-1) { SAFE_FREE(buffer_s); return strcmp(ps, pt); /* Not quite the right answer, but finding the right one under this failure case is expensive, and it's pretty close */ } ret = strcasecmp_w(buffer_s, buffer_t); SAFE_FREE(buffer_s); SAFE_FREE(buffer_t); return ret;}/** Case insensitive string compararison, length limited.**/int StrnCaseCmp(const char *s, const char *t, size_t n){ pstring buf1, buf2; unix_strupper(s, strlen(s)+1, buf1, sizeof(buf1)); unix_strupper(t, strlen(t)+1, buf2, sizeof(buf2)); return strncmp(buf1,buf2,n);}/** * Compare 2 strings. * * @note The comparison is case-insensitive. **/BOOL strequal(const char *s1, const char *s2){ if (s1 == s2) return(True); if (!s1 || !s2) return(False); return(StrCaseCmp(s1,s2)==0);}/** * Compare 2 strings up to and including the nth char. * * @note The comparison is case-insensitive. **/BOOL strnequal(const char *s1,const char *s2,size_t n){ if (s1 == s2) return(True); if (!s1 || !s2 || !n) return(False); return(StrnCaseCmp(s1,s2,n)==0);}/** Compare 2 strings (case sensitive).**/BOOL strcsequal(const char *s1,const char *s2){ if (s1 == s2) return(True); if (!s1 || !s2) return(False); return(strcmp(s1,s2)==0);}/**Do a case-insensitive, whitespace-ignoring string compare.**/int strwicmp(const char *psz1, const char *psz2){ /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */ /* appropriate value. */ if (psz1 == psz2) return (0); else if (psz1 == NULL) return (-1); else if (psz2 == NULL) return (1); /* sync the strings on first non-whitespace */ while (1) { while (isspace((int)*psz1)) psz1++; while (isspace((int)*psz2)) psz2++; if (toupper_ascii(*psz1) != toupper_ascii(*psz2) || *psz1 == '\0' || *psz2 == '\0') break; psz1++; psz2++; } return (*psz1 - *psz2);}/** Convert a string to upper case, but don't modify it.**/char *strupper_static(const char *s){ static pstring str; pstrcpy(str, s); strupper_m(str); return str;}/** Convert a string to "normal" form.**/void strnorm(char *s, int case_default){ if (case_default == CASE_UPPER) strupper_m(s); else strlower_m(s);}/** Check if a string is in "normal" case.**/BOOL strisnormal(const char *s, int case_default){ if (case_default == CASE_UPPER) return(!strhaslower(s)); return(!strhasupper(s));}/** String replace. NOTE: oldc and newc must be 7 bit characters**/void string_replace( pstring s, char oldc, char newc ){ char *p; /* this is quite a common operation, so we want it to be fast. We optimise for the ascii case, knowing that all our supported multi-byte character sets are ascii-compatible (ie. they match for the first 128 chars) */ for (p = s; *p; p++) { if (*p & 0x80) /* mb string - slow path. */ break; if (*p == oldc) *p = newc; } if (!*p) return; /* Slow (mb) path. */#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS /* With compose characters we must restart from the beginning. JRA. */ p = s;#endif push_ucs2(NULL, tmpbuf, p, sizeof(tmpbuf), STR_TERMINATE); string_replace_w(tmpbuf, UCS2_CHAR(oldc), UCS2_CHAR(newc)); pull_ucs2(NULL, p, tmpbuf, -1, sizeof(tmpbuf), STR_TERMINATE);}/** Skip past some strings in a buffer.**/char *skip_string(char *buf,size_t n){ while (n--) buf += strlen(buf) + 1; return(buf);}/** Count the number of characters in a string. Normally this will be the same as the number of bytes in a string for single byte strings, but will be different for multibyte.**/size_t str_charnum(const char *s){ uint16 tmpbuf2[sizeof(pstring)]; push_ucs2(NULL, tmpbuf2,s, sizeof(tmpbuf2), STR_TERMINATE); return strlen_w(tmpbuf2);}/** Count the number of characters in a string. Normally this will be the same as the number of bytes in a string for single byte strings, but will be different for multibyte.**/size_t str_ascii_charnum(const char *s){ pstring tmpbuf2; push_ascii(tmpbuf2, s, sizeof(tmpbuf2), STR_TERMINATE); return strlen(tmpbuf2);}BOOL trim_char(char *s,char cfront,char cback){ BOOL ret = False; char *ep; char *fp = s; /* Ignore null or empty strings. */ if (!s || (s[0] == '\0')) return False; if (cfront) { while (*fp && *fp == cfront) fp++; if (!*fp) { /* We ate the string. */ s[0] = '\0'; return True; } if (fp != s) ret = True; } ep = fp + strlen(fp) - 1; if (cback) { /* Attempt ascii only. Bail for mb strings. */ while ((ep >= fp) && (*ep == cback)) { ret = True; if ((ep > fp) && (((unsigned char)ep[-1]) & 0x80)) { /* Could be mb... bail back to tim_string. */ char fs[2], bs[2]; if (cfront) { fs[0] = cfront; fs[1] = '\0'; } bs[0] = cback; bs[1] = '\0'; return trim_string(s, cfront ? fs : NULL, bs); } else { ep--; } } if (ep < fp) { /* We ate the string. */ s[0] = '\0'; return True; } } ep[1] = '\0'; memmove(s, fp, ep-fp+2); return ret;}/** Trim the specified elements off the front and back of a string.**/BOOL trim_string(char *s,const char *front,const char *back){ BOOL ret = False; size_t front_len; size_t back_len; size_t len; /* Ignore null or empty strings. */ if (!s || (s[0] == '\0')) return False; front_len = front? strlen(front) : 0; back_len = back? strlen(back) : 0; len = strlen(s); if (front_len) { while (len && strncmp(s, front, front_len)==0) { /* Must use memmove here as src & dest can * easily overlap. Found by valgrind. JRA. */ memmove(s, s+front_len, (len-front_len)+1); len -= front_len; ret=True; } } if (back_len) { while ((len >= back_len) && strncmp(s+len-back_len,back,back_len)==0) { s[len-back_len]='\0'; len -= back_len; ret=True; } } return ret;}/** Does a string have any uppercase chars in it?**/BOOL strhasupper(const char *s){ smb_ucs2_t *ptr; push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE); for(ptr=tmpbuf;*ptr;ptr++) if(isupper_w(*ptr)) return True; return(False);}/** Does a string have any lowercase chars in it?**/BOOL strhaslower(const char *s){ smb_ucs2_t *ptr; push_ucs2(NULL, tmpbuf,s, sizeof(tmpbuf), STR_TERMINATE); for(ptr=tmpbuf;*ptr;ptr++) if(islower_w(*ptr)) return True; return(False);}/** Find the number of 'c' chars in a string**/size_t count_chars(const char *s,char c){ smb_ucs2_t *ptr; int count; smb_ucs2_t *alloc_tmpbuf = NULL; if (push_ucs2_allocate(&alloc_tmpbuf, s) == (size_t)-1) { return 0; } for(count=0,ptr=alloc_tmpbuf;*ptr;ptr++) if(*ptr==UCS2_CHAR(c)) count++; SAFE_FREE(alloc_tmpbuf); return(count);}/** Safe string copy into a known length string. maxlength does not include the terminating zero.**/char *safe_strcpy_fn(const char *fn, int line, char *dest,const char *src, size_t maxlength){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -