Browse code

Merge commit 'origin/daniel/pv'

* commit 'origin/daniel/pv':
fix add/lookup pv name
fix pv&t lookup due to signness
pv api updates
- list of PVs types syncronized with Kamailio

Conflicts:
pvapi.c

Andrei Pelinescu-Onciul authored on 19/12/2008 13:57:57
Showing 3 changed files
... ...
@@ -34,18 +34,18 @@
34 34
 #include "mem/shm_mem.h"
35 35
 #include "ut.h"
36 36
 #include "dprint.h"
37
-#include "hashes.h"
37
+#include "hash_func.h"
38 38
 #include "pvar.h"
39 39
 
40 40
 #define is_in_str(p, in) (p<in->s+in->len && *p)
41
+#define core_hash(in, a, b) get_hash1_raw((in)->s, (in)->len)
41 42
 
42 43
 #define PV_TABLE_SIZE	16
43
-#define TR_TABLE_SIZE	2
44
+#define TR_TABLE_SIZE	4
44 45
 
45 46
 
46 47
 void tr_destroy(trans_t *t);
47 48
 void tr_free(trans_t *t);
48
-void tr_param_free(tr_param_t *tp);
49 49
 
50 50
 typedef struct _pv_item
51 51
 {
... ...
@@ -61,7 +61,7 @@ static int _pv_table_set = 0;
61 61
 /**
62 62
  *
63 63
  */
64
-void pv_init_table()
64
+void pv_init_table(void)
65 65
 {
66 66
 	memset(_pv_table, 0, sizeof(pv_item_t*)*PV_TABLE_SIZE);
67 67
 	_pv_table_set = 1;
... ...
@@ -89,7 +89,7 @@ int pv_table_add(pv_export_t *e)
89 89
 	pv_item_t *pvj = NULL;
90 90
 	pv_item_t *pvn = NULL;
91 91
 	int found;
92
-	int pvid;
92
+	unsigned int pvid;
93 93
 
94 94
 	if(e==NULL || e->name.s==NULL || e->getf==NULL || e->type==PVT_NONE)
95 95
 	{
... ...
@@ -112,20 +112,18 @@ int pv_table_add(pv_export_t *e)
112 112
 		return -1;
113 113
 	}
114 114
 	found = 0;
115
-	pvid = get_hash1_raw(in->s, in->len);
115
+	//pvid = get_hash1_raw(in->s, in->len);
116
+	pvid = core_hash(in, 0, 0);
116 117
 
117 118
 	pvi = _pv_table[pvid%PV_TABLE_SIZE];
118 119
 	while(pvi)
119 120
 	{
120 121
 		if(pvi->pvid > pvid)
121 122
 			break;
122
-		if(pvi->pve.name.len > in->len)
123
-			break;
124 123
 		if(pvi->pve.name.len==in->len)
125 124
 		{
126 125
 			found = strncmp(pvi->pve.name.s, in->s, in->len);
127
-			if(found>0)
128
-				break;
126
+
129 127
 			if(found==0)
130 128
 			{
131 129
 				LM_ERR("pvar [%.*s] already exists\n", in->len, in->s);
... ...
@@ -239,7 +237,7 @@ int pv_get_sintval(struct sip_msg *msg, pv_param_t *param,
239 237
 	if(res==NULL)
240 238
 		return -1;
241 239
 
242
-	ch = int2str(sival, &l);
240
+	ch = sint2str(sival, &l);
243 241
 	res->rs.s = ch;
244 242
 	res->rs.len = l;
245 243
 
... ...
@@ -326,14 +324,13 @@ pv_export_t* pv_lookup_spec_name(str *pvname, pv_spec_p e)
326 324
 	}
327 325
 
328 326
 	/* search in PV table */
329
-	pvid = get_hash1_raw(pvname->s, pvname->len);
327
+	// pvid = get_hash1_raw(pvname->s, pvname->len);
328
+	pvid = core_hash(pvname, 0, 0);
330 329
 	pvi = _pv_table[pvid%PV_TABLE_SIZE];
331 330
 	while(pvi)
332 331
 	{
333 332
 		if(pvi->pvid > pvid)
334 333
 			break;
335
-		if(pvi->pve.name.len > pvname->len)
336
-			break;
337 334
 
338 335
 		if(pvi->pvid==pvid && pvi->pve.name.len==pvname->len
339 336
 			&& memcmp(pvi->pve.name.s, pvname->s, pvname->len)==0)
... ...
@@ -352,6 +349,71 @@ pv_export_t* pv_lookup_spec_name(str *pvname, pv_spec_p e)
352 349
 	return NULL;
353 350
 }
354 351
 
352
+int pv_parse_index(pv_spec_p sp, str *in)
353
+{
354
+	char *p;
355
+	char *s;
356
+	int sign;
357
+	pv_spec_p nsp = 0;
358
+
359
+	if(in==NULL || in->s==NULL || sp==NULL)
360
+		return -1;
361
+	p = in->s;
362
+	if(*p==PV_MARKER)
363
+	{
364
+		nsp = (pv_spec_p)pkg_malloc(sizeof(pv_spec_t));
365
+		if(nsp==NULL)
366
+		{
367
+			LM_ERR("no more memory\n");
368
+			return -1;
369
+		}
370
+		s = pv_parse_spec(in, nsp);
371
+		if(s==NULL)
372
+		{
373
+			LM_ERR("invalid index [%.*s]\n", in->len, in->s);
374
+			pv_spec_free(nsp);
375
+			return -1;
376
+		}
377
+		sp->pvp.pvi.type = PV_IDX_PVAR;
378
+		sp->pvp.pvi.u.dval = (void*)nsp;
379
+		return 0;
380
+	}
381
+	if(*p=='*' && in->len==1)
382
+	{
383
+		sp->pvp.pvi.type = PV_IDX_ALL;
384
+		return 0;
385
+	}
386
+	sign = 1;
387
+	if(*p=='-')
388
+	{
389
+		sign = -1;
390
+		p++;
391
+	}
392
+	sp->pvp.pvi.u.ival = 0;
393
+	while(p<in->s+in->len && *p>='0' && *p<='9')
394
+	{
395
+		sp->pvp.pvi.u.ival = sp->pvp.pvi.u.ival * 10 + *p - '0';
396
+		p++;
397
+	}
398
+	if(p!=in->s+in->len)
399
+	{
400
+		LM_ERR("invalid index [%.*s]\n", in->len, in->s);
401
+		return -1;
402
+	}
403
+	sp->pvp.pvi.u.ival *= sign;
404
+	sp->pvp.pvi.type = PV_IDX_INT;
405
+	return 0;
406
+}
407
+
408
+int pv_init_iname(pv_spec_p sp, int param)
409
+{
410
+	if(sp==NULL)
411
+		return -1;
412
+	sp->pvp.pvn.type = PV_NAME_INTSTR;
413
+	sp->pvp.pvn.u.isname.name.n = param;
414
+	return 0;
415
+}
416
+
355 417
 char* pv_parse_spec2(str *in, pv_spec_p e, int silent)
356 418
 {
357 419
 	char *p;
... ...
@@ -721,6 +783,122 @@ error:
721 783
 	return -1;
722 784
 }
723 785
 
786
+int pv_get_spec_name(struct sip_msg* msg, pv_param_p ip, pv_value_t *name)
787
+{
788
+	if(msg==NULL || ip==NULL || name==NULL)
789
+		return -1;
790
+	memset(name, 0, sizeof(pv_value_t));
791
+
792
+	if(ip->pvn.type==PV_NAME_INTSTR)
793
+	{
794
+		if(ip->pvn.u.isname.type&AVP_NAME_STR)
795
+		{
796
+			name->rs = ip->pvn.u.isname.name.s;
797
+			name->flags = PV_VAL_STR;
798
+		} else {
799
+			name->ri = ip->pvn.u.isname.name.n;
800
+			name->flags = PV_VAL_INT|PV_TYPE_INT;
801
+		}
802
+		return 0;
803
+	} else if(ip->pvn.type==PV_NAME_INTSTR) {
804
+		/* pvar */
805
+		if(pv_get_spec_value(msg, (pv_spec_p)(ip->pvn.u.dname), name)!=0)
806
+		{
807
+			LM_ERR("cannot get name value\n");
808
+			return -1;
809
+		}
810
+		if(name->flags&PV_VAL_NULL || name->flags&PV_VAL_EMPTY)
811
+		{
812
+			LM_ERR("null or empty name\n");
813
+			return -1;
814
+		}
815
+		return 0;
816
+	}
817
+	LM_ERR("name type is PV_NAME_OTHER - cannot resolve\n");
818
+	return -1;
819
+}
820
+
821
+int pv_get_avp_name(struct sip_msg* msg, pv_param_p ip, int_str *avp_name,
822
+		unsigned short *name_type)
823
+{
824
+	pv_value_t tv;
825
+	if(ip==NULL || avp_name==NULL || name_type==NULL)
826
+		return -1;
827
+	memset(avp_name, 0, sizeof(int_str));
828
+	*name_type = 0;
829
+
830
+	if(ip->pvn.type==PV_NAME_INTSTR)
831
+	{
832
+		*name_type = ip->pvn.u.isname.type;
833
+		if(ip->pvn.u.isname.type&AVP_NAME_STR)
834
+		{
835
+			avp_name->s = ip->pvn.u.isname.name.s;
836
+			*name_type |= AVP_NAME_STR;
837
+		} else {
838
+			avp_name->n = ip->pvn.u.isname.name.n;
839
+			/* *name_type &= AVP_SCRIPT_MASK; */
840
+			*name_type = 0;
841
+		}
842
+		return 0;
843
+	}
844
+	/* pvar */
845
+	if(pv_get_spec_value(msg, (pv_spec_p)(ip->pvn.u.dname), &tv)!=0)
846
+	{
847
+		LM_ERR("cannot get avp value\n");
848
+		return -1;
849
+	}
850
+	if(tv.flags&PV_VAL_NULL || tv.flags&PV_VAL_EMPTY)
851
+	{
852
+		LM_ERR("null or empty name\n");
853
+		return -1;
854
+	}
855
+		
856
+	if((tv.flags&PV_TYPE_INT) && (tv.flags&PV_VAL_INT))
857
+	{
858
+		avp_name->n = tv.ri;
859
+	} else {
860
+		avp_name->s = tv.rs;
861
+		*name_type = AVP_NAME_STR;
862
+	}
863
+	return 0;
864
+}
865
+
866
+
867
+int pv_get_spec_index(struct sip_msg* msg, pv_param_p ip, int *idx, int *flags)
868
+{
869
+	pv_value_t tv;
870
+	if(ip==NULL || idx==NULL || flags==NULL)
871
+		return -1;
872
+
873
+	*idx = 0;
874
+	*flags = 0;
875
+
876
+	if(ip->pvi.type == PV_IDX_ALL) {
877
+		*flags = PV_IDX_ALL;
878
+		return 0;
879
+	}
880
+	
881
+	if(ip->pvi.type == PV_IDX_INT)
882
+	{
883
+		*idx = ip->pvi.u.ival;
884
+		return 0;
885
+	}
886
+
887
+	/* pvar */
888
+	if(pv_get_spec_value(msg, (pv_spec_p)ip->pvi.u.dval, &tv)!=0)
889
+	{
890
+		LM_ERR("cannot get index value\n");
891
+		return -1;
892
+	}
893
+	if(!(tv.flags&PV_VAL_INT))
894
+	{
895
+		LM_ERR("invalid index value\n");
896
+		return -1;
897
+	}
898
+	*idx = tv.ri;
899
+	return 0;
900
+}
901
+
724 902
 int pv_get_spec_value(struct sip_msg* msg, pv_spec_p sp, pv_value_t *value)
725 903
 {
726 904
 	int ret = 0;
... ...
@@ -737,6 +915,7 @@ int pv_get_spec_value(struct sip_msg* msg, pv_spec_p sp, pv_value_t *value)
737 915
 	ret = (*sp->getf)(msg, &(sp->pvp), value);
738 916
 	if(ret!=0)
739 917
 		return ret;
918
+		
740 919
 	if(sp->trans)
741 920
 		return tr_exec(msg, (trans_t*)sp->trans, value);
742 921
 	return ret;
... ...
@@ -814,6 +993,73 @@ done:
814 993
 	return 0;
815 994
 }
816 995
 
996
+/**
997
+ *
998
+ */
999
+pvname_list_t* parse_pvname_list(str *in, unsigned int type)
1000
+{
1001
+	pvname_list_t* head = NULL;
1002
+	pvname_list_t* al = NULL;
1003
+	pvname_list_t* last = NULL;
1004
+	char *p;
1005
+	pv_spec_t spec;
1006
+	str s;
1007
+
1008
+	if(in==NULL || in->s==NULL)
1009
+	{
1010
+		LM_ERR("bad parameters\n");
1011
+		return NULL;
1012
+	}
1013
+
1014
+	p = in->s;
1015
+	while(is_in_str(p, in))
1016
+	{
1017
+		while(is_in_str(p, in) && (*p==' '||*p=='\t'||*p==','||*p==';'))
1018
+			p++;
1019
+		if(!is_in_str(p, in))
1020
+		{
1021
+			if(head==NULL)
1022
+				LM_ERR("wrong item name list [%.*s]\n", in->len, in->s);
1023
+			return head;
1024
+		}
1025
+		s.s=p;
1026
+		s.len = in->s+in->len-p;
1027
+		p = pv_parse_spec(&s, &spec);
1028
+		if(p==NULL || (type && spec.type!=type))
1029
+		{
1030
+			LM_ERR("wrong item name list [%.*s]!\n", in->len, in->s);
1031
+			goto error;
1032
+		}
1033
+		al = (pvname_list_t*)pkg_malloc(sizeof(pvname_list_t));
1034
+		if(al==NULL)
1035
+		{
1036
+			LM_ERR("no more memory!\n");
1037
+			goto error;
1038
+		}
1039
+		memset(al, 0, sizeof(pvname_list_t));
1040
+		memcpy(&al->sname, &spec, sizeof(pv_spec_t));
1041
+
1042
+		if(last==NULL)
1043
+		{
1044
+			head = al;
1045
+			last = al;
1046
+		} else {
1047
+			last->next = al;
1048
+			last = al;
1049
+		}
1050
+	}
1051
+
1052
+	return head;
1053
+
1054
+error:
1055
+	while(head)
1056
+	{
1057
+		al = head;
1058
+		head=head->next;
1059
+		pkg_free(al);
1060
+	}
1061
+	return NULL;
1062
+}
817 1063
 
818 1064
 /**
819 1065
  *
... ...
@@ -853,6 +1099,23 @@ void pv_value_destroy(pv_value_t *val)
853 1099
 	memset(val, 0, sizeof(pv_value_t));
854 1100
 }
855 1101
 
1102
+#define PV_PRINT_BUF_SIZE  1024
1103
+#define PV_PRINT_BUF_NO    3
1104
+int pv_printf_s(struct sip_msg* msg, pv_elem_p list, str *s)
1105
+{
1106
+	static int buf_itr = 0;
1107
+	static char buf[PV_PRINT_BUF_NO][PV_PRINT_BUF_SIZE];
1108
+
1109
+	if (list->next==0 && list->spec.getf==0) {
1110
+		*s = list->text;
1111
+		return 0;
1112
+	} else {
1113
+		s->s = buf[buf_itr];
1114
+		s->len = PV_PRINT_BUF_SIZE;
1115
+		buf_itr = (buf_itr+1)%PV_PRINT_BUF_NO;
1116
+		return pv_printf( msg, list, s->s, &s->len);
1117
+	}
1118
+}
856 1119
 
857 1120
 /********************************************************
858 1121
  * Transformations API
... ...
@@ -879,7 +1142,7 @@ static inline char* tr_get_class(str *in, char *p, str *tclass)
879 1142
 /**
880 1143
  *
881 1144
  */
882
-static inline trans_t* tr_new()
1145
+static inline trans_t* tr_new(void)
883 1146
 {
884 1147
 	trans_t *t = NULL;
885 1148
 
... ...
@@ -984,6 +1247,14 @@ void tr_destroy(trans_t *t)
984 1247
 	memset(t, 0, sizeof(trans_t));
985 1248
 }
986 1249
 
1250
+/*!
1251
+ * \brief Exec transformation on a pseudo-variable value
1252
+ * \param msg SIP message
1253
+ * \param tr one or more transformations
1254
+ * \param val pseudo-variable value
1255
+ * \return 0 on success, -1 on error
1256
+ */
1257
+
987 1258
 int tr_exec(struct sip_msg *msg, trans_t *t, pv_value_t *v)
988 1259
 {
989 1260
 	int r;
... ...
@@ -1048,14 +1319,14 @@ typedef struct _tr_item
1048 1319
 	struct _tr_item *next;
1049 1320
 } tr_item_t, *tr_item_p;
1050 1321
 
1051
-static tr_item_t* _tr_table[PV_TABLE_SIZE];
1322
+static tr_item_t* _tr_table[TR_TABLE_SIZE];
1052 1323
 static int _tr_table_set = 0;
1053 1324
 
1054 1325
 
1055 1326
 /**
1056 1327
  *
1057 1328
  */
1058
-void tr_init_table()
1329
+void tr_init_table(void)
1059 1330
 {
1060 1331
 	memset(_tr_table, 0, sizeof(tr_item_t*)*TR_TABLE_SIZE);
1061 1332
 	_tr_table_set = 1;
... ...
@@ -1070,7 +1341,7 @@ int tr_table_add(tr_export_t *e)
1070 1341
 	tr_item_t *trj = NULL;
1071 1342
 	tr_item_t *trn = NULL;
1072 1343
 	int found;
1073
-	int trid;
1344
+	unsigned int trid;
1074 1345
 
1075 1346
 	if(e==NULL || e->tclass.s==NULL)
1076 1347
 	{
... ...
@@ -1085,9 +1356,10 @@ int tr_table_add(tr_export_t *e)
1085 1356
 	}
1086 1357
 
1087 1358
 	found = 0;
1088
-	trid = get_hash1_raw(e->tclass.s, e->tclass.len);
1359
+	// trid = get_hash1_raw(e->tclass.s, e->tclass.len);
1360
+	trid = core_hash(&e->tclass, 0, 0);
1089 1361
 
1090
-	tri = _tr_table[trid%PV_TABLE_SIZE];
1362
+	tri = _tr_table[trid%TR_TABLE_SIZE];
1091 1363
 	while(tri)
1092 1364
 	{
1093 1365
 		if(tri->trid > trid)
... ...
@@ -1120,10 +1392,12 @@ int tr_table_add(tr_export_t *e)
1120 1392
 	memcpy(&(trn->tre), e, sizeof(tr_export_t));
1121 1393
 	trn->trid = trid;
1122 1394
 
1395
+	//LM_DBG("TR class [%.*s] added to entry [%d]\n", e->tclass.len,
1396
+	//					e->tclass.s, trid%TR_TABLE_SIZE);
1123 1397
 	if(trj==0)
1124 1398
 	{
1125
-		trn->next = _tr_table[trid%PV_TABLE_SIZE];
1126
-		_tr_table[trid%PV_TABLE_SIZE] = trn;
1399
+		trn->next = _tr_table[trid%TR_TABLE_SIZE];
1400
+		_tr_table[trid%TR_TABLE_SIZE] = trn;
1127 1401
 		goto done;
1128 1402
 	}
1129 1403
 	trn->next = trj->next;
... ...
@@ -1191,7 +1465,8 @@ tr_export_t* tr_lookup_class(str *tclass)
1191 1465
 	}
1192 1466
 
1193 1467
 	/* search in TR table */
1194
-	trid = get_hash1_raw(tclass->s, tclass->len);
1468
+	// trid = get_hash1_raw(tclass->s, tclass->len);
1469
+	trid = core_hash(tclass, 0, 0);
1195 1470
 	tri = _tr_table[trid%TR_TABLE_SIZE];
1196 1471
 	while(tri)
1197 1472
 	{
... ...
@@ -1209,3 +1484,8 @@ tr_export_t* tr_lookup_class(str *tclass)
1209 1484
 	return NULL;
1210 1485
 }
1211 1486
 
1487
+void pv_api_destroy(void)
1488
+{
1489
+	/* free PV and TR hash tables */
1490
+	return;
1491
+}
... ...
@@ -57,6 +57,7 @@
57 57
 
58 58
 #define PV_NAME_INTSTR	0
59 59
 #define PV_NAME_PVAR	1
60
+#define PV_NAME_OTHER	2
60 61
 
61 62
 #define PV_IDX_INT	0
62 63
 #define PV_IDX_PVAR	1
... ...
@@ -72,7 +73,11 @@
72 73
 
73 74
 enum _pv_type { 
74 75
 	PVT_NONE=0,           PVT_EMPTY,             PVT_NULL, 
75
-	PVT_MARKER,           PVT_AVP,               PVT_COLOR,
76
+	PVT_MARKER,           PVT_AVP,               PVT_HDR,
77
+	PVT_RURI,             PVT_RURI_USERNAME,     PVT_RURI_DOMAIN,
78
+	PVT_DSTURI,           PVT_COLOR,             PVT_BRANCH,
79
+	PVT_FROM,             PVT_TO,                PVT_OURI,
80
+	PVT_SCRIPTVAR,        PVT_MSG_BODY,          PVT_CONTEXT,
76 81
 	PVT_OTHER,            PVT_EXTRA /* keep it last */
77 82
 };
78 83
 
... ...
@@ -161,7 +166,6 @@ typedef struct _pv_elem
161 166
 char* pv_parse_spec2(str *in, pv_spec_p sp, int silent);
162 167
 #define pv_parse_spec(in, sp) pv_parse_spec2((in), (sp), 0)
163 168
 int pv_get_spec_value(struct sip_msg* msg, pv_spec_p sp, pv_value_t *value);
164
-int pv_print_spec(struct sip_msg* msg, pv_spec_p sp, char *buf, int *len);
165 169
 int pv_printf(struct sip_msg* msg, pv_elem_p list, char *buf, int *len);
166 170
 int pv_elem_free_all(pv_elem_p log);
167 171
 void pv_value_destroy(pv_value_t *val);
... ...
@@ -172,8 +176,10 @@ int pv_get_avp_name(struct sip_msg* msg, pv_param_p ip, int_str *avp_name,
172 176
 		unsigned short *name_type);
173 177
 int pv_get_spec_name(struct sip_msg* msg, pv_param_p ip, pv_value_t *name);
174 178
 int pv_parse_format(str *in, pv_elem_p *el);
179
+int pv_parse_index(pv_spec_p sp, str *in);
175 180
 int pv_init_iname(pv_spec_p sp, int param);
176 181
 int pv_printf_s(struct sip_msg* msg, pv_elem_p list, str *s);
182
+void pv_api_destroy(void);
177 183
 
178 184
 typedef struct _pvname_list {
179 185
 	pv_spec_t sname;
... ...
@@ -191,10 +197,7 @@ int register_pvars_mod(char *mod_name, pv_export_t *items);
191 197
 int pv_free_extra_list(void);
192 198
 
193 199
 /*! \brief PV helper functions */
194
-int pv_parse_index(pv_spec_p sp, str *in);
195
-
196 200
 int pv_get_null(struct sip_msg *msg, pv_param_t *param, pv_value_t *res);
197
-int pv_update_time(struct sip_msg *msg, time_t *t);
198 201
 
199 202
 int pv_get_uintval(struct sip_msg *msg, pv_param_t *param,
200 203
 		pv_value_t *res, unsigned int uival);
... ...
@@ -218,7 +221,7 @@ int pv_get_intstrval(struct sip_msg *msg, pv_param_t *param,
218 221
 #define TR_PARAM_MARKER		','
219 222
 
220 223
 enum _tr_param_type { TR_PARAM_NONE=0, TR_PARAM_STRING, TR_PARAM_NUMBER,
221
-	TR_PARAM_SPEC };
224
+	TR_PARAM_SPEC, TR_PARAM_SUBST, TR_PARAM_OTHER };
222 225
 
223 226
 typedef struct _tr_param {
224 227
 	int type;
... ...
@@ -250,6 +253,9 @@ typedef struct _tr_export {
250 253
 char* tr_lookup(str *in, trans_t **tr);
251 254
 tr_export_t* tr_lookup_class(str *tclass);
252 255
 int tr_exec(struct sip_msg *msg, trans_t *t, pv_value_t *v);
256
+void tr_param_free(tr_param_t *tp);
257
+
258
+int register_trans_mod(char *mod_name, tr_export_t *items);
253 259
 
254 260
 #endif
255 261
 
... ...
@@ -299,6 +299,27 @@ static inline char* int2str(unsigned int l, int* len)
299 299
 	return &r[i+1];
300 300
 }
301 301
 
302
+/* Signed INTeger-TO-STRing: convers a long to a string
303
+ * returns a pointer to a static buffer containing l in asciiz & sets len */
304
+static inline char* sint2str(long l, int* len)
305
+{
306
+	int sign;
307
+	char *p;
308
+
309
+	sign = 0;
310
+	if(l<0) {
311
+		sign = 1;
312
+		l = -l;
313
+	}
314
+	p = int2str((unsigned long)l, len);
315
+	if(sign) {
316
+		*(--p) = '-';
317
+		if (len) (*len)++;
318
+	}
319
+	return p;
320
+}
321
+
322
+
302 323
 
303 324
 
304 325
 #define USHORT2SBUF_MAX_LEN  5 /* 65535*/