7fa84b41 |
/*
*$Id$
*
* - various general purpose functions
|
7dd0b342 |
*
* Copyright (C) 2001-2003 Fhg Fokus
*
* This file is part of ser, a free SIP server.
*
* ser 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
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
b6e94c57 |
*
* History
* ------
* 2003-01-18 un_escape function introduced for convenience of code needing
* the complex&slow feature of unescaping
|
6b6f226f |
* 2003-01-28 scratchpad removed (jiri)
* 2003-01-29 pathmax added (jiri)
* 2003-02-13 strlower added (janakj)
* 2003-02-28 scratchpad compatibility abandoned (jiri)
* 2003-03-30 str2int and str2float added (janakj)
* 2003-04-26 ZSW (jiri)
|
7fa84b41 |
*/
|
7dd0b342 |
|
7fa84b41 |
#ifndef ut_h
#define ut_h
|
049f64c2 |
#include "comp_defs.h"
|
fb9d2755 |
#include <sys/types.h>
#include <sys/time.h>
|
049f64c2 |
#include <limits.h>
|
fb9d2755 |
#include <unistd.h>
|
5c4113af |
#include <ctype.h>
|
fb9d2755 |
|
049f64c2 |
#include "config.h"
|
7fa84b41 |
#include "dprint.h"
|
b6e94c57 |
#include "str.h"
|
7fa84b41 |
|
caf80ae6 |
struct sip_msg;
|
6b6f226f |
/* zero-string wrapper */
#define ZSW(_c) ((_c)?(_c):"")
|
dda9dab1 |
/* returns string beginning and length without insignificant chars */
#define trim_len( _len, _begin, _mystr ) \
|
51eadd0c |
do{ static char _c; \
|
dda9dab1 |
(_len)=(_mystr).len; \
|
e3fc93f4 |
while ((_len) && ((_c=(_mystr).s[(_len)-1])==0 || _c=='\r' || \
_c=='\n' || _c==' ' || _c=='\t' )) \
|
dda9dab1 |
(_len)--; \
(_begin)=(_mystr).s; \
while ((_len) && ((_c=*(_begin))==' ' || _c=='\t')) { \
(_len)--;\
(_begin)++; \
} \
|
51eadd0c |
}while(0)
|
dda9dab1 |
#define trim_r( _mystr ) \
|
9c61e9f9 |
do{ static char _c; \
|
e22bbdb8 |
while( ((_mystr).len) && ( ((_c=(_mystr).s[(_mystr).len-1]))==0 ||\
_c=='\r' || _c=='\n' ) \
) \
|
dda9dab1 |
(_mystr).len--; \
|
51eadd0c |
}while(0)
|
dda9dab1 |
|
327a9bd5 |
#define translate_pointer( _new_buf , _org_buf , _p) \
( (_p)?(_new_buf + (_p-_org_buf)):(0) )
|
4457a3c2 |
#define via_len(_via) \
((_via)->bsize-((_via)->name.s-\
((_via)->hdr.s+(_via)->hdr.len)))
|
caf80ae6 |
/* char to hex conversion table */
static char fourbits2char[16] = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
327a9bd5 |
|
3d2e8729 |
/* converts a str to an u. short, returns the u. short and sets *err on
|
7fa84b41 |
* error and if err!=null
|
51eadd0c |
*/
|
6419a43f |
static inline unsigned short str2s(char* s, unsigned int len,
|
7fa84b41 |
int *err)
{
unsigned short ret;
int i;
unsigned char *limit;
unsigned char *init;
|
6419a43f |
unsigned char* str;
|
3d2e8729 |
|
7fa84b41 |
/*init*/
|
6419a43f |
str=(unsigned char*)s;
|
7fa84b41 |
ret=i=0;
limit=str+len;
init=str;
|
3d2e8729 |
|
7fa84b41 |
for(;str<limit ;str++){
if ( (*str <= '9' ) && (*str >= '0') ){
ret=ret*10+*str-'0';
i++;
if (i>5) goto error_digits;
}else{
//error unknown char
goto error_char;
}
}
if (err) *err=0;
return ret;
|
3d2e8729 |
|
7fa84b41 |
error_digits:
|
5a33102b |
DBG("str2s: ERROR: too many letters in [%.*s]\n", (int)len, init);
|
7fa84b41 |
if (err) *err=1;
return 0;
error_char:
|
5a33102b |
DBG("str2s: ERROR: unexpected char %c in %.*s\n", *str, (int)len, init);
|
7fa84b41 |
if (err) *err=1;
return 0;
}
|
3d2e8729 |
static inline int btostr( char *p, unsigned char val)
{
unsigned int a,b,i =0;
|
7fa84b41 |
|
3d2e8729 |
if ( (a=val/100)!=0 )
*(p+(i++)) = a+'0'; /*first digit*/
if ( (b=val%100/10)!=0 || a)
*(p+(i++)) = b+'0'; /*second digit*/
*(p+(i++)) = '0'+val%10; /*third digit*/
return i;
}
|
74ed389d |
#define INT2STR_MAX_LEN 11 /* 10 digits + 0 */
|
3d2e8729 |
|
6419a43f |
/* returns a pointer to a static buffer containing l in asciiz & sets len */
|
09f7cd2c |
static inline char* int2str(unsigned int l, int* len)
{
|
74ed389d |
static char r[INT2STR_MAX_LEN];
|
09f7cd2c |
int i;
i=9;
r[10]=0; /* null terminate */
do{
r[i]=l%10+'0';
i--;
l/=10;
}while(l && (i>=0));
if (l && (i<0)){
LOG(L_CRIT, "BUG: int2str: overflow\n");
}
if (len) *len=9-i;
return &r[i+1];
}
|
3d2e8729 |
/* faster memchr version */
|
7fa84b41 |
static inline char* q_memchr(char* p, int c, unsigned int size)
{
char* end;
end=p+size;
for(;p<end;p++){
if (*p==(unsigned char)c) return p;
}
return 0;
}
|
caf80ae6 |
inline static int reverse_hex2int( char *c, int len )
|
fa377d6b |
{
char *pc;
int r;
char mychar;
r=0;
for (pc=c+len-1; len>0; pc--, len--) {
r <<= 4 ;
mychar=*pc;
if ( mychar >='0' && mychar <='9') r+=mychar -'0';
else if (mychar >='a' && mychar <='f') r+=mychar -'a'+10;
else if (mychar >='A' && mychar <='F') r+=mychar -'A'+10;
else return -1;
}
return r;
}
inline static int int2reverse_hex( char **c, int *size, int nr )
{
unsigned short digit;
if (*size && nr==0) {
**c = '0';
(*c)++;
(*size)--;
return 1;
}
while (*size && nr ) {
digit = nr & 0xf ;
**c= digit >= 10 ? digit + 'a' - 10 : digit + '0';
nr >>= 4;
(*c)++;
(*size)--;
}
return nr ? -1 /* number not processed; too little space */ : 1;
}
|
caf80ae6 |
/* double output length assumed ; does NOT zero-terminate */
inline static int string2hex(
/* input */ unsigned char *str, int len,
/* output */ char *hex )
{
int orig_len;
if (len==0) {
*hex='0';
return 1;
}
orig_len=len;
while ( len ) {
*hex=fourbits2char[(*str) >> 4];
hex++;
*hex=fourbits2char[(*str) & 0xf];
hex++;
len--;
str++;
}
return orig_len-len;
}
|
d17d750b |
|
f51155cf |
/* portable sleep in microseconds (no interrupt handling now) */
|
fb9d2755 |
inline static void sleep_us( unsigned int nusecs )
{
struct timeval tval;
tval.tv_sec=nusecs/100000;
tval.tv_usec=nusecs%1000000;
select(0, NULL, NULL, NULL, &tval );
}
|
049f64c2 |
/* portable determination of max_path */
inline static int pathmax()
{
#ifdef PATH_MAX
static int pathmax=PATH_MAX;
#else
static int pathmax=0;
#endif
if (pathmax==0) { /* init */
pathmax=pathconf("/", _PC_PATH_MAX);
pathmax=(pathmax<=0)?PATH_MAX_GUESS:pathmax+1;
}
return pathmax;
}
|
b6e94c57 |
inline static int hex2int(char hex_digit)
{
if (hex_digit>='0' && hex_digit<='9')
return hex_digit-'0';
if (hex_digit>='a' && hex_digit<='f')
return hex_digit-'a'+10;
if (hex_digit>='A' && hex_digit<='F')
return hex_digit-'A'+10;
/* no valid hex digit ... */
LOG(L_ERR, "ERROR: hex2int: '%c' is no hex char\n", hex_digit );
return -1;
}
/* Un-escape URI user -- it takes a pointer to original user
str, as well as the new, unescaped one, which MUST have
an allocated buffer linked to the 'str' structure ;
(the buffer can be allocated with the same length as
the original string -- the output string is always
shorter (if escaped characters occur) or same-long
as the original one).
only printeable characters are permitted
<0 is returned on an uneascaping error, length of the
unescaped string otherwise
*/
inline static int un_escape(str *user, str *new_user )
{
int i, j, value;
int hi, lo;
|
5ddda324 |
if( new_user==0 || new_user->s==0) {
LOG(L_CRIT, "BUG: un_escape: called with invalid param\n");
return -1;
}
|
b6e94c57 |
new_user->len = 0;
j = 0;
for (i = 0; i < user->len; i++) {
if (user->s[i] == '%') {
if (i + 2 >= user->len) {
LOG(L_ERR, "ERROR: un_escape: escape sequence too short in"
" '%.*s' @ %d\n",
user->len, user->s, i );
goto error;
}
hi=hex2int(user->s[i + 1]);
if (hi<0) {
LOG(L_ERR, "ERROR: un_escape: non-hex high digit in an escape sequence in"
" '%.*s' @ %d\n",
user->len, user->s, i+1 );
goto error;
}
lo=hex2int(user->s[i + 2]);
if (lo<0) {
LOG(L_ERR, "ERROR: non-hex low digit in an escape sequence in "
"'%.*s' @ %d\n",
user->len, user->s, i+2 );
goto error;
}
value=(hi<<4)+lo;
if (value < 32 || value > 126) {
LOG(L_ERR, "ERROR: non-ASCII escaped character in '%.*s' @ %d\n",
user->len, user->s, i );
goto error;
}
new_user->s[j] = value;
i+=2; /* consume the two hex digits, for cycle will move to the next char */
} else {
new_user->s[j] = user->s[i];
}
j++; /* good -- we translated another character */
}
new_user->len = j;
return j;
error:
new_user->len = j;
return -1;
}
|
5c4113af |
/*
* Convert a string to lower case
*/
static inline void strlower(str* _s)
{
int i;
for(i = 0; i < _s->len; i++) {
_s->s[i] = tolower(_s->s[i]);
}
}
|
b6420530 |
/*
* Convert a str into integer
*/
static inline int str2int(str* _s, unsigned int* _r)
{
int i;
*_r = 0;
for(i = 0; i < _s->len; i++) {
if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
*_r *= 10;
*_r += _s->s[i] - '0';
} else {
return -1;
}
}
return 0;
}
/*
* Convert a str to float
*/
static inline int str2float(str* _s, float* _r)
{
int i, dot = 0;
float order = 0.1;
*_r = 0;
for(i = 0; i < _s->len; i++) {
if (_s->s[i] == '.') {
if (dot) return -1;
dot = 1;
continue;
}
if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
if (dot) {
*_r += (_s->s[i] - '0') * order;
order /= 10;
} else {
*_r *= 10;
*_r += _s->s[i] - '0';
}
} else {
return -2;
}
}
return 0;
}
|
7fa84b41 |
#endif
|