/* * $Id: util.c,v 1.1.1.1 2004/08/25 19:22:00 jan Exp $ * * Copyright (c) 2002 Jan Algermissen * See the file "COPYING" for copying permission. * */ #include "tmutil.h" #include "tmtrace.h" #include "tmassert.h" #include static int ansiToLower(int c); int tm_chomp(char *buf,size_t n) { assert(buf); while(buf[n-1] == '\n' || buf[n-1] == '\r') buf[--n] = '\0'; return n; } void tm_free_keys(const void *key,void **value, void *cl) { void *k = (void*)key; TM_FREE((TMPool)cl,k); } char *tm_tolowercase(const char *s, char *buf,size_t size) { char *p = buf; assert(s); assert(buf); while(*s && size) { *p = tolower(*s); p++,s++,size--; } *p = '\0'; return buf; } char x2c(char *what) { char digit; digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); digit *= 16; digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); return digit; } char * tm_url_unescape(char *url) { int x,y; for(x=0,y=0;url[y];++x,++y) { if( (url[x] = url[y]) == '%') { url[x] = x2c(&url[y+1]); y+=2; } } url[x] = '\0'; return url; } int _is_in(char c, const char *delims) { for ( ; *delims; delims++) { /* if(c == *delims || ((c) < '!' || (c) > '~' )) */ if(c == *delims) { /* fprintf(stderr,"%c (%d) is in delims\n",c,c); */ return 1; } } /* fprintf(stderr,"%c (%d) is not in delims\n",c,c); */ return 0; } char *tm_strtok(const char **strp,const char *delims,char *buf, size_t size) { const char *p,*d; const char *end; const char *source = *strp; int match,len; /* fprintf(stderr,"source: _%s_\n",source); */ while(*source && _is_in(*source,delims) ) source++; /* fprintf(stderr,"source: _%s_\n",source); */ end = p = source; if(!*p) { *buf = '\0'; return NULL; } match = 0; while(*p && !match) { for (d = delims; *d; d++) { /* if(*p == *d || ((*p) < '!' || (*p) > '~' )) */ if(*p == *d) { end = p; while(*(p+1) && _is_in(*(p+1),delims) ) p++; match = 1; break; } } p++; if(!match) end = p; } /* len = *p ? (p - source - 1) : (p - source); */ len = end - source; assert( len < size); strncpy(buf,source,len); buf[len] = '\0'; /* fprintf(stderr,"word: _%s_\n",buf); */ *strp = p; return buf; } char *tm_strdup(TMPool pool,const char *s) { char *t; /* FIXME: allow this or not ?? */ if(!s) return NULL; TMTRACE(TM_X_TRACE,"allocating space for _%s_\n" _ s); t = (char *)TM_ALLOC(pool,strlen(s)+1); assert(t); strcpy(t,s); return t; } char *tm_strndup(TMPool pool,const char *s, int len) { char *t; /* FIXME: allow this or not ?? */ if(!s) return NULL; t = (char *)TM_ALLOC(pool,len+1); assert(t); memcpy(t,s,len); t[len] = '\0'; return t; } void tm_fmtprint(TMPool pool,FILE *f, const char *s, int indent, int width, int start_indent) { int ind; int first = 1; char word[64]; char *line; assert(s); line = TM_ALLOC(pool,(width+1) * sizeof(char)); bzero(line, (width+1)*sizeof(char) ); ind = start_indent; while( tm_strtok(&s," \t",word,sizeof(word)) != NULL) { assert(strlen(word) < width); /* FIXME */ if(strlen(line) + 1 + strlen(word) > width) { fprintf(f,"%*s%s\n", ind,"",line); bzero(line, (width+1)*sizeof(char) ); if(first) { first = 0; ind = indent; } } if(strlen(line) == 0) strcat(line,word); else { strcat(line," "); strcat(line,word); } } fprintf(f,"%*s%s\n", ind,"",line); TM_FREE(pool,line); } int tm_strcmp_v(const void *lhs, const void *rhs) { return strcmp((const char*)lhs,(const char*)rhs); } /* unsigned int tm_strhash_v(const void *what) { char *s = (char *)what; unsigned long h = 0; while (*s) h = (h << 5) + h + (unsigned char)*s++; return h; } */ unsigned int tm_strhash_v(const void *what) { unsigned char *s; unsigned int h = 0; for(s=(unsigned char *)what; *s; s++) h = 31 * h + *s; return h; } int tm_strendswith(const char *haystack, const char *needle) { int pos; pos = strlen(haystack) - strlen(needle); if(pos < 0) return 0; haystack += pos; return ( ! strcmp(haystack,needle)); } /* FIXME: size checks and real normalization! */ int tm_uri_normalize(const char *uri, char *buf, size_t size) { assert(uri); assert(buf); assert( tm_uri_is_abs(uri) ); assert(size > (strlen(uri)+20) ); /* FIXME! */ if(*uri == '/') { snprintf(buf,size,"file://%s",uri); } else { strcpy(buf,uri); } /* FIXME: retval */ return 0; } /* FIXME: what does snprintf return ?? */ int tm_uri_from_id(const char *doc_uri, const char *id, char *buf,size_t size) { int n; assert(doc_uri); assert(id); assert(buf); assert((strlen(doc_uri)+1+strlen(id)) < size); n = snprintf(buf,size,"%s#%s",doc_uri,id); return n; } /* Most is FIXME */ int tm_uri_from_ref(const char *doc_uri,const char *ref,char *buf,size_t size) { assert(doc_uri); assert(ref); assert(buf); if(*ref == '#') { snprintf(buf,size,"%s%s",doc_uri,ref); } else if(tm_uri_is_abs(ref)) { tm_uri_normalize(ref,buf,size); } else { char *p_last_slash = strrchr(doc_uri,'/'); bzero(buf,size); /* doc uri MUST have file portion !! * FIXME: check that is the setters !! */ assert(p_last_slash); strncpy(buf,doc_uri, (p_last_slash - doc_uri + 1) ); /* is 0 terminated, because we bzero-ed */ strcat(buf,ref); /* FIXME: strNcat !! */ /* fprintf(stderr,"-->_%s_\n",doc_uri); fprintf(stderr,"-->_%s_\n",href); fprintf(stderr,"-->_%s_\n",buf); */ } /* FIXME: retval? */ return 0; } int tm_uri_is_abs(const char *uri) { assert(uri); if(*uri == '/') return 1; if(strstr(uri,"://") != NULL) return 1; return 0; } int tm_is_whitespace_string(const char *s) { assert(s); while(*s) { if( ! isspace(*s) ) return 0; s++; } return 1; } int tm_is_comment_string(const char *s, char c) { assert(s); while(*s) { if( ! isspace(*s)) { if(*s == c) /* is comment */ return (1); else return 0; } s++; } return 1; } const char *tm_lstrip(const char *str) { assert(str); while( *str && isspace(*str) ) str++; return str; } /* FIXME: all implementation and also consider locale and Unicode stuff!!!, maybe we ned encoding as a param? */ const char * tm_strstr(const char *haystack,const char* needle,int cs) { int nlen; int hlen; const char *h; if(cs == TM_CASE_SENSITIVE) return( strstr(haystack,needle) ); hlen = strlen(haystack); nlen = strlen(needle); for(h = haystack; *h; h++,hlen--) { const char *p,*q; int equal = 1; /* assume */ if(hlen < nlen) return NULL; p = h; q = needle; while( *q ) { if(ansiToLower(*p) != ansiToLower(*q)) { equal = 0; break; } p++; q++; } if(equal) return h; } return NULL; } /** * Convert an ANSI character to lowercase. * FIXME: whole function! also, UTF8 issue!! * */ int ansiToLower(int c) { if(c >= 65 && c <= 90) return c + 32; if(c >= 192 && c <= 214) return c + 32; if(c >= 216 && c <= 222) return c + 32; if(c == 140) return 156; if(c == 138) return 154; if(c == 159) return 255; return c; } /* int tm_strcmp_ci(copnst char *lhs,const char*rhs) { } */ #if 0 #include "tmtk.h" #include "tmutil.h" #include "tmassert.h" #include #define __MAXLINE__ 1024 /** * check, if the pattern fragment is found in str. cs stands for * 'match case sensitiv', so set to 1 if that's what you desire. * 20.02.2000 */ int contains(const char *strarg, const char *fragarg,int cs) { int plen,flen,i,j; int match = 0; char *p,*f; char str[__MAXLINE__]; char fragment[__MAXLINE__]; char str_cpy[__MAXLINE__], fragment_cpy[__MAXLINE__]; strcpy(str,strarg); strcpy(fragment,fragarg); plen = strlen(str); flen = strlen(fragment); /* fragment bigger that phrase, can't be inside */ if(plen < flen) return 0; /* * if not case-sensitive, we have to make local copy, * and change upper case letters to lower case * so we do not have to check for upper case each time ! */ if(cs) { p = str; f = fragment; } else { strcpy(str_cpy,str); strcpy(fragment_cpy,fragment); /* TODO: check for letters above ASCII 127 (ΔάΦ...) */ for(p = str_cpy; *p != '\0'; p++) { if( (*p >= 'A') && (*p <= 'Z')) *p += 32; } p = str_cpy; for(f = fragment_cpy; *f != '\0'; f++) { if( (*f >= 'A') && (*f <= 'Z')) *f += 32; } f = fragment_cpy; } for(i = 0; i <= plen - flen; i++) { match = 1; for(j = 0; j < flen; j++) { if( (p[i+j] != f[j]) ) { match = 0; break; } } if(match) break; } return match; } /** * check if s starts with f. This is always done case insensitive * (this is used for the KwicTextfiels for Update Program) * 20.02.2000 */ int begins_with2(const char *s, const char *f) { const char *ps, *pf; pf = f; ps = s; while( (*pf != '\0') ) { if(*ps == '\0') return 0; /* too short */ if(*ps != *pf) return 0; /* if(*ps != *pf) { if( (*ps >= 'A' && *ps <= 'Z') && (*ps+32 != *pf)) return 0; else if( (*pf >= 'A' && *pf <= 'Z') && (*pf+32 != *ps)) return 0; } */ ps++; pf++; } return 1; /* yes, s starts with f */ } int begins_with(const char *strarg, const char *fragarg,int cs) { int plen,flen,j; int match = 0; char *p,*f; char str_cpy[__MAXLINE__], fragment_cpy[__MAXLINE__]; char str[__MAXLINE__]; char fragment[__MAXLINE__]; strcpy(str,strarg); strcpy(fragment,fragarg); plen = strlen(str); flen = strlen(fragment); /* fragment bigger that phrase, can't be inside */ if(plen < flen) return 0; /* * if not case-sensitive, we have to make local copy, * and change upper case letters to lower case * so we do not have to check for upper case each time ! */ if(cs) { p = str; f = fragment; } else { strcpy(str_cpy,str); strcpy(fragment_cpy,fragment); /* TODO: check for letters above ASCII 127 (ΔάΦ...) */ for(p = str_cpy; *p != '\0'; p++) { if( (*p >= 'A') && (*p <= 'Z')) *p += 32; } p = str_cpy; for(f = fragment_cpy; *f != '\0'; f++) { if( (*f >= 'A') && (*f <= 'Z')) *f += 32; } f = fragment_cpy; } match = 1; for(j = 0; j < flen; j++) { if( (p[j] != f[j]) ) { match = 0; break; } } return match; } /** * xx. * yy. */ int srb_match(const char *str,const char *pattern,int flags) { /* while( *s != '\0' && *pattern != '\0') { if(*s != *pattern) return 0; s++; pattern++; } if(*pattern != '\0') return 0; else return 1; */ return 0; } /** * Perform a case insensitive strcmp. * Using the Ansi ASCII extension */ int srb_strequal(const char *s1,const char* s2,int cs) { if(cs) { while( *s1 != '\0' && *s2 != '\0') { if(*s1 != *s2) return 0; s1++; s2++; } if(*s1 != '\0' || *s2 != '\0') return 0; return 1; } else { while( *s1 != '\0' && *s2 != '\0') { if(ansiToLower(*s1) != ansiToLower(*s2)) return 0; s1++; s2++; } if(*s1 != '\0' || *s2 != '\0') return 0; return 1; } } /*@} */ #endif