/* Copyright (c) 2000-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file dkstr.c String functions module. */ #include "dk.h" #include "dkmem.h" #if DK_HAVE_STRING_H #include #endif #if DK_HAVE_WCHAR_H #include #endif #if DK_HAVE_CTYPE_H #include #endif $(trace-include) /** Inside the dkstr module. */ #define DK_STR_C 1 #include "dkstr.h" int dkstr_casecmp DK_P2(char *, a, char *, b) { int back = 0; #if DK_HAVE_STRCASECMP $? "+ dkstr_casecmp strcasecmp %s %s", TR_STR(a), TR_STR(b) back = strcasecmp(a,b); #else #if DK_HAVE_STRICMP || DK_HAVE__STRICMP $? "+ dkstr_casecmp stricmp %s %s", TR_STR(a), TR_STR(b) #if DK_HAVE_STRICMP back = stricmp(a,b); #else back = _stricmp(a,b); #endif #else int ende; char aval, bval, *aptr, *bptr; $? "+ dkstr_casecmp fallback %s %s", TR_STR(a), TR_STR(b) if(a && b) { aptr = a; bptr = b; ende = 0; while((ende == 0) && (back == 0)) { aval = *aptr; bval = *bptr; if(aval && bval) { if(islower(aval)) aval = toupper(aval); if(islower(bval)) bval = toupper(bval); if(aval != bval) { ende = 1; if(aval > bval) back = 1; else back = -1; } else { aptr++; bptr++; } } else { ende = 1; if(aval) { back = 1; } if(bval) { back = -1; } } } } #endif #endif $? "- dkstr_casecmp %d", back return back; } char *dkstr_dup DK_P1(char *, p) { char *back = NULL; $? "+ dkstr_dup %s", TR_STR(p) if(p) { size_t len; len = strlen(p); len++; back = dk_new(char,len); if(back) { strcpy(back,p); } } $? "- dkstr_dup %s", TR_STR(back) return back; } char * dkstr_chr DK_P2(char *, str, int, c) { char *back = NULL; $? "+ dkstr_chr %s %d", TR_STR(str), c if(str) { #if DK_HAVE_STRCHR back = strchr(str,c); #else char *ptr; ptr = str; while((*ptr) && (!back)) { if(((int)(*ptr)) == c) { back = ptr; } else { ptr++; } } #endif } $? "- dkstr_chr %s", TR_STR(back) return back; } char * dkstr_rchr DK_P2(char *, str, int, c) { char *back = NULL; if(str) { #if DK_HAVE_STRRCHR back = strrchr(str,c); #else char *ptr; ptr = str; while(*ptr) { if(((int)(*ptr)) == c) { back = ptr; } ptr++; } #endif } return back; } /** The set of whitespace characters. */ static char default_whitespace_set[] = { " \t\r\n" }; char * dkstr_start DK_P2(char *, str, char *, whsp) { char *back = NULL; char *ptr, *wh; $? "+ dkstr_start %s", TR_STR(str) if(str) { wh = (whsp ? whsp : default_whitespace_set); ptr = str; while((*ptr) && (!back)) { if(dkstr_chr(wh,((int)(*ptr)))) { ptr++; } else { back = ptr; } } } $? "- dkstr_start %s", TR_STR(back) return back; } void dkstr_chomp DK_P2(char *, str, char *, whsp) { char *wh; char *ptr; char *x; $? "+ dkstr_chomp %s", TR_STR(str) if(str) { wh = (whsp ? whsp : default_whitespace_set); x = NULL; ptr = str; while(*ptr) { if(dkstr_chr(wh,((int)(*ptr)))) { if(!x) { x = ptr; } } else { x = NULL; } ptr++; } if(x) { *x = '\0'; } } $? "- dkstr_chomp %s", TR_STR(str) } char * dkstr_next DK_P2(char *, str, char *, whsp) { char *back = NULL; char *ptr, *wh; int state; $? "+ dkstr_next %s", TR_STR(str) if(str) { ptr = str; wh = (whsp ? whsp : default_whitespace_set); state = 0; while((state < 2) && (*ptr)) { if(dkstr_chr(wh,((int)(*ptr)))) { if(state == 1) { state = 2; *(ptr++) = '\0'; back = dkstr_start(ptr,wh); } ptr++; } else { state = 1; ptr++; } } } $? "- dkstr_next %s", TR_STR(back) return back; } /** Keywords to set boolean values. */ static char *bool_keywords[] = { (char *)"0", (char *)"n$o", (char *)"of$f", (char *)"f$alse", (char *)"-", (char *)"+", (char *)"1", (char *)"y$es", (char *)"on", (char *)"ok", (char *)"t$rue", NULL }; int dkstr_is_bool DK_P1(char *, str) { int back = 0; $? "+ dkstr_is_bool %s", TR_STR(str) if(str) { if(dkstr_array_abbr(bool_keywords,str,'$',0) >= 0) { back = 1; } } $? "- dkstr_is_bool %d", back return back; } int dkstr_is_on DK_P1(char *, str) { int back = 0; $? "+ dkstr_is_on %s",TR_STR(str) if(str) { if(dkstr_array_abbr(&(bool_keywords[5]),str,'$',0) >= 0) { back = 1; } } $? "- dkstr_is_on %d", back return back; } int dkstr_array_index DK_P3(char **, array, char *, str, int, cs) { int back = -1; char **ptr; int i; $? "+ dkstr_array_index %s %s %d", TR_PTR(array), TR_STR(str), cs if(array && str) { i = 0; ptr = array; while((*ptr) && (back == -1)) { if(cs) { if(strcmp(*ptr,str) == 0) { back = i; } } else { if(dkstr_casecmp(*ptr,str) == 0) { back = i; } } if(back == -1) { ptr++; i++; } } } $? "- dkstr_array_index %d", back return back; } /** Find length of an array. @param cmd The array. @return Number of strings in the array. */ static int array_length DK_P1(char **, cmd) { int back = -1; if(cmd) { back = 0; while(*(cmd++)) { back++; } } return back; } int dkstr_find_multi_part_cmd DK_P3(char **, cmd, char ***, cmdset, int, cs) { int back = -1; char ***lfdcmdset; int l1, l2, i, running, this_is_it; if(cmd && cmdset) { lfdcmdset = cmdset; l1 = array_length(cmd); running = 0; while((back == -1) && *lfdcmdset) { l2 = array_length(*lfdcmdset); if(l1 == l2) { this_is_it = 1; for(i = 0; i < l1; i++) { if(cs) { if(strcmp(cmd[i], (*lfdcmdset)[i])) { this_is_it = 0; } } else { if(dkstr_casecmp(cmd[i], (*lfdcmdset)[i])) { this_is_it = 0; } } } if(this_is_it) { back = running; } } lfdcmdset++; running++; } } return back; } /** Wide characters which represent whitespaces. */ static wchar_t default_w_whitespace_set[] = { (wchar_t)' ', (wchar_t)'\t', (wchar_t)'\r', (wchar_t)'\n', (wchar_t)0 }; wchar_t * dkstr_w_chr DK_P2(wchar_t *, str, wchar_t, c) { wchar_t *back = NULL; #if !DK_HAVE_WCSCHR wchar_t *ptr; #endif if(str) { #if DK_HAVE_WCSCHR back = wcschr(str,c); #else ptr = str; while((*ptr) && (!back)) { if(*ptr == c) { back = ptr; } ptr++; } #endif } return back; } wchar_t * dkstr_w_rchr DK_P2(wchar_t *, str, wchar_t, c) { wchar_t *back = NULL; #if !DK_HAVE_WCSRCHR wchar_t *ptr; #endif if(str) { #if DK_HAVE_WCSRCHR back = wcsrchr(str,c); #else ptr = str; while(*ptr) { if(*ptr == c) { back = ptr; } ptr++; } #endif } return back; } wchar_t * dkstr_w_start DK_P2(wchar_t *, str, wchar_t *, whsp) { wchar_t *back = NULL; wchar_t *w, *ptr; if(str) { w = (whsp ? whsp : default_w_whitespace_set); ptr = str; while((*ptr) && (!back)) { if(!dkstr_w_chr(w,*ptr)) { back = ptr; } ptr++; } } return back; } void dkstr_w_chomp DK_P2(wchar_t *, str, wchar_t *, whsp) { wchar_t *back = NULL; wchar_t *ptr, *w; w = (whsp ? whsp : default_w_whitespace_set); ptr = str; while(*ptr) { if(!dkstr_w_chr(w,*ptr)) { back = ptr; } ptr++; } if(back) { back++; *back = (wchar_t)0; } } wchar_t * dkstr_w_next DK_P2(wchar_t *, str, wchar_t *, whsp) { wchar_t *back = NULL; wchar_t *w, *ptr; w = (whsp ? whsp : default_w_whitespace_set); ptr = dkstr_w_start(str,w); if(ptr) { while((*ptr) && (!back)) { if(dkstr_w_chr(w,*ptr)) { back = ptr; } ptr++; } if(back) { *(back++) = (wchar_t)0; back = dkstr_w_start(back,w); } } return back; } int dkstr_w_casecmp DK_P2(wchar_t *, a, wchar_t *, b) { int back = 0; if(a && b) { #if DK_HAVE_WCSCASECMP && DK_HAVE_WCHAR_H back = wcscasecmp(a,b); #else #if DK_HAVE_WCSICMP back = wcsicmp(a,b); #else int cc; wchar_t c1, c2, *ptr1, *ptr2; ptr1 = a; ptr2 = b; cc = 1; while(cc) { if(*ptr1) { if(*ptr2) { c1 = *ptr1; c2 = *ptr2; if((c1 >= 65) && (c1 <= 90)) { c1 += 32; } if((c2 >= 65) && (c2 <= 90)) { c2 += 32; } if(c1 > c2) { back = 1; cc = 0; } else { if(c1 < c2) { back = -1; cc = 0; } else { ptr1++; ptr2++; } } } else { back = 1; cc = 0; } } else { if(*ptr2) { back = -1; cc = 0; } else { cc = 0; } } } #endif #endif } else { if(a) { back = 1; } else { back = -1; } } return back; } int dkstr_w_cmp DK_P2(wchar_t *, a, wchar_t *, b) { int back = 0; #if !DK_HAVE_WCSCMP int cc; wchar_t c1, c2, *ptr1, *ptr2; #endif if(a && b) { #if DK_HAVE_WCSCMP back = wcscmp(a,b); #else ptr1 = a; ptr2 = b; cc = 1; while(cc) { if(*ptr1) { if(*ptr2) { c1 = *ptr1; c2 = *ptr2; if(c1 > c2) { back = 1; cc = 0; } else { if(c1 < c2) { back = -1; cc = 0; } else { ptr1++; ptr2++; } } } else { back = 1; cc = 0; } } else { if(*ptr2) { back = -1; cc = 0; } else { cc = 0; } } } #endif } else { if(a) { back = 1; } else { back = -1; } } return back; } size_t dkstr_w_len DK_P1(wchar_t *, str) { size_t back = 0; #if !DK_HAVE_WCSLEN wchar_t *ptr; #endif if(str) { #if DK_HAVE_WCSLEN back = wcslen(str); #else ptr = str; while(*ptr) { ptr++; back++; } #endif } return back; } void dkstr_w_cpy DK_P2(wchar_t *, d, wchar_t *, s) { #if DK_HAVE_WCSCPY if(d && s) { wcscpy(d,s); } #else wchar_t *sptr, *dptr; if(d && s) { dptr = d; sptr = s; while(*sptr) { *(dptr++) = *(sptr++); } *dptr = (wchar_t)0; } #endif } wchar_t * dkstr_w_dup DK_P1(wchar_t *, str) { wchar_t *back = NULL; size_t lgt; if(str) { lgt = dkstr_w_len(str); lgt++; back = dk_new(wchar_t,lgt); if(back) { dkstr_w_cpy(back,str); } } return back; } size_t dkstr_explode DK_P4(char **,array,size_t,sz,char *,str,char *,whsp) { size_t back = 0; char *wh, *current, *next; char **ptr; size_t i; if(array && (sz > 1) && str) { wh = (whsp ? whsp : default_whitespace_set); ptr = array; i = sz; while(i--) { *(ptr++) = NULL; } ptr = array; i = 0; current = dkstr_start(str, wh); while(current && (i < (sz - 1))) { next = dkstr_next(current,wh); *(ptr++) = current; i++; back++; current = next; } } return back; } size_t dkstr_w_explode DK_P4(wchar_t **,array,size_t,sz,wchar_t *,str,wchar_t *,whsp) { size_t back = 0; wchar_t *wh, *current, *next; wchar_t **ptr; size_t i; if(array && (sz > 1) && str) { wh = (whsp ? whsp : default_w_whitespace_set); ptr = array; i = sz; while(i--) { *(ptr++) = NULL; } ptr = array; i = 0; current = dkstr_w_start(str, wh); while(current && (i < (sz - 1))) { next = dkstr_w_next(current,wh); *(ptr++) = current; i++; back++; current = next; } } return back; } int dkstr_is_abbr DK_P4(char *,line,char *,pattern,char,spec,int,cs) { int back = 0; char cl, cp, *lptr, *pptr; int afterspec, cc; $? "+ dkstr_is_abbr %s %s %c %d", TR_STR(line), TR_STR(pattern), spec, cs if(line && pattern) { lptr = line; pptr = pattern; afterspec = 0; cc = 1; while(cc) { if(*pptr) { if((!afterspec) && (*pptr == spec)) { afterspec = 1; pptr++; } else { if(*lptr) { cl = *lptr; cp = *pptr; if(!cs) { if(islower(cl)) cl = toupper(cl); if(islower(cp)) cp = toupper(cp); } if(cl == cp) { lptr++; pptr++; } else { cc = 0; back = 0; } } else { cc = 0; if(afterspec) back = 1; } } } else { cc = 0; if(!(*lptr)) { back = 1; } } } } $? "- dkstr_is_abbr %d", back return back; } int dkstr_array_abbr DK_P4(char **, array, char *, str, char, sp, int, cs) { int back = -1; char **ptr; int i; $? "+ dkstr_array_abbr %s %s %d", TR_PTR(array), TR_STR(str), cs if(array && str) { i = 0; ptr = array; while((*ptr) && (back == -1)) { $? ". i=%d ptr=%s", i, TR_STR(*ptr) if(dkstr_is_abbr(str,*ptr,sp,cs)) { back = i; } if(back == -1) { ptr++; i++; } $? ". back=%d", back } } $? "- dkstr_array_abbr %d", back return back; } int dkstr_find_multi_part_abbr DK_P4(char **,cmd,char ***,cmdset,char,s,int,cs) { int back = -1; char ***lfdcmdset; int l1, l2, i, running, this_is_it; if(cmd && cmdset) { lfdcmdset = cmdset; l1 = array_length(cmd); running = 0; while((back == -1) && *lfdcmdset) { l2 = array_length(*lfdcmdset); if(l1 == l2) { this_is_it = 1; for(i = 0; i < l1; i++) { if(!dkstr_is_abbr(cmd[i],(*lfdcmdset)[i],s,cs)) { this_is_it = 0; } } if(this_is_it) { back = running; } } lfdcmdset++; running++; } } return back; } /** Characters allowed as first character of an identifier. */ static char id_start[] = { "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" }; /** Characters allowed after the first character of an identifier. */ static char id_cont[] = { "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" }; int dkstr_is_identifier DK_P1(char *,s) { int back = 0; char *ptr; $? "+ dkstr_is_identifier %s", TR_STR(s) if(s) { ptr = s; if(dkstr_chr(id_start, *ptr)) { back = 1; ptr++; while(back && (*ptr)) { if(!dkstr_chr(id_cont, *ptr)) { back = 0; } ptr++; } } } $? "- dkstr_is_identifier %d", back return back; } char * dkstr_unquote DK_P2(char *,str,char *,quo) { char *back = NULL; char c, *ptr; $? "+ dkstr_unquote %s %s", TR_STR(str), TR_STR(quo) if(str) { back = str; if(dkstr_chr(quo, *back)) { c = *(back++); ptr = dkstr_rchr(back, c); if(ptr) { *ptr = '\0'; } } } $? "- dkstr_unquote %s", TR_STR(back) return back; }