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 239
 	if(res==NULL)
240 240
 		return -1;
241 241
 
242
-	ch = int2str(sival, &l);
242
+	ch = sint2str(sival, &l);
243 243
 	res->rs.s = ch;
244 244
 	res->rs.len = l;
245 245
 
... ...
@@ -326,14 +324,13 @@ pv_export_t* pv_lookup_spec_name(str *pvname, pv_spec_p e)
326 326
 	}
327 327
 
328 328
 	/* search in PV table */
329
-	pvid = get_hash1_raw(pvname->s, pvname->len);
329
+	// pvid = get_hash1_raw(pvname->s, pvname->len);
330
+	pvid = core_hash(pvname, 0, 0);
330 331
 	pvi = _pv_table[pvid%PV_TABLE_SIZE];
331 332
 	while(pvi)
332 333
 	{
333 334
 		if(pvi->pvid > pvid)
334 335
 			break;
335
-		if(pvi->pve.name.len > pvname->len)
336
-			break;
337 336
 
338 337
 		if(pvi->pvid==pvid && pvi->pve.name.len==pvname->len
339 338
 			&& 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 352
 	return NULL;
353 353
 }
354 354
 
355
+int pv_parse_index(pv_spec_p sp, str *in)
356
+{
357
+	char *p;
358
+	char *s;
359
+	int sign;
360
+	pv_spec_p nsp = 0;
361
+
362
+	if(in==NULL || in->s==NULL || sp==NULL)
363
+		return -1;
364
+	p = in->s;
365
+	if(*p==PV_MARKER)
366
+	{
367
+		nsp = (pv_spec_p)pkg_malloc(sizeof(pv_spec_t));
368
+		if(nsp==NULL)
369
+		{
370
+			LM_ERR("no more memory\n");
371
+			return -1;
372
+		}
373
+		s = pv_parse_spec(in, nsp);
374
+		if(s==NULL)
375
+		{
376
+			LM_ERR("invalid index [%.*s]\n", in->len, in->s);
377
+			pv_spec_free(nsp);
378
+			return -1;
379
+		}
380
+		sp->pvp.pvi.type = PV_IDX_PVAR;
381
+		sp->pvp.pvi.u.dval = (void*)nsp;
382
+		return 0;
383
+	}
384
+	if(*p=='*' && in->len==1)
385
+	{
386
+		sp->pvp.pvi.type = PV_IDX_ALL;
387
+		return 0;
388
+	}
389
+	sign = 1;
390
+	if(*p=='-')
391
+	{
392
+		sign = -1;
393
+		p++;
394
+	}
395
+	sp->pvp.pvi.u.ival = 0;
396
+	while(p<in->s+in->len && *p>='0' && *p<='9')
397
+	{
398
+		sp->pvp.pvi.u.ival = sp->pvp.pvi.u.ival * 10 + *p - '0';
399
+		p++;
400
+	}
401
+	if(p!=in->s+in->len)
402
+	{
403
+		LM_ERR("invalid index [%.*s]\n", in->len, in->s);
404
+		return -1;
405
+	}
406
+	sp->pvp.pvi.u.ival *= sign;
407
+	sp->pvp.pvi.type = PV_IDX_INT;
408
+	return 0;
409
+}
410
+
411
+int pv_init_iname(pv_spec_p sp, int param)
412
+{
413
+	if(sp==NULL)
414
+		return -1;
415
+	sp->pvp.pvn.type = PV_NAME_INTSTR;
416
+	sp->pvp.pvn.u.isname.name.n = param;
417
+	return 0;
418
+}
419
+
355 420
 char* pv_parse_spec2(str *in, pv_spec_p e, int silent)
356 421
 {
357 422
 	char *p;
... ...
@@ -721,6 +783,122 @@ error:
721 721
 	return -1;
722 722
 }
723 723
 
724
+int pv_get_spec_name(struct sip_msg* msg, pv_param_p ip, pv_value_t *name)
725
+{
726
+	if(msg==NULL || ip==NULL || name==NULL)
727
+		return -1;
728
+	memset(name, 0, sizeof(pv_value_t));
729
+
730
+	if(ip->pvn.type==PV_NAME_INTSTR)
731
+	{
732
+		if(ip->pvn.u.isname.type&AVP_NAME_STR)
733
+		{
734
+			name->rs = ip->pvn.u.isname.name.s;
735
+			name->flags = PV_VAL_STR;
736
+		} else {
737
+			name->ri = ip->pvn.u.isname.name.n;
738
+			name->flags = PV_VAL_INT|PV_TYPE_INT;
739
+		}
740
+		return 0;
741
+	} else if(ip->pvn.type==PV_NAME_INTSTR) {
742
+		/* pvar */
743
+		if(pv_get_spec_value(msg, (pv_spec_p)(ip->pvn.u.dname), name)!=0)
744
+		{
745
+			LM_ERR("cannot get name value\n");
746
+			return -1;
747
+		}
748
+		if(name->flags&PV_VAL_NULL || name->flags&PV_VAL_EMPTY)
749
+		{
750
+			LM_ERR("null or empty name\n");
751
+			return -1;
752
+		}
753
+		return 0;
754
+	}
755
+	LM_ERR("name type is PV_NAME_OTHER - cannot resolve\n");
756
+	return -1;
757
+}
758
+
759
+int pv_get_avp_name(struct sip_msg* msg, pv_param_p ip, int_str *avp_name,
760
+		unsigned short *name_type)
761
+{
762
+	pv_value_t tv;
763
+	if(ip==NULL || avp_name==NULL || name_type==NULL)
764
+		return -1;
765
+	memset(avp_name, 0, sizeof(int_str));
766
+	*name_type = 0;
767
+
768
+	if(ip->pvn.type==PV_NAME_INTSTR)
769
+	{
770
+		*name_type = ip->pvn.u.isname.type;
771
+		if(ip->pvn.u.isname.type&AVP_NAME_STR)
772
+		{
773
+			avp_name->s = ip->pvn.u.isname.name.s;
774
+			*name_type |= AVP_NAME_STR;
775
+		} else {
776
+			avp_name->n = ip->pvn.u.isname.name.n;
777
+			/* *name_type &= AVP_SCRIPT_MASK; */
778
+			*name_type = 0;
779
+		}
780
+		return 0;
781
+	}
782
+	/* pvar */
783
+	if(pv_get_spec_value(msg, (pv_spec_p)(ip->pvn.u.dname), &tv)!=0)
784
+	{
785
+		LM_ERR("cannot get avp value\n");
786
+		return -1;
787
+	}
788
+	if(tv.flags&PV_VAL_NULL || tv.flags&PV_VAL_EMPTY)
789
+	{
790
+		LM_ERR("null or empty name\n");
791
+		return -1;
792
+	}
793
+		
794
+	if((tv.flags&PV_TYPE_INT) && (tv.flags&PV_VAL_INT))
795
+	{
796
+		avp_name->n = tv.ri;
797
+	} else {
798
+		avp_name->s = tv.rs;
799
+		*name_type = AVP_NAME_STR;
800
+	}
801
+	return 0;
802
+}
803
+
804
+
805
+int pv_get_spec_index(struct sip_msg* msg, pv_param_p ip, int *idx, int *flags)
806
+{
807
+	pv_value_t tv;
808
+	if(ip==NULL || idx==NULL || flags==NULL)
809
+		return -1;
810
+
811
+	*idx = 0;
812
+	*flags = 0;
813
+
814
+	if(ip->pvi.type == PV_IDX_ALL) {
815
+		*flags = PV_IDX_ALL;
816
+		return 0;
817
+	}
818
+	
819
+	if(ip->pvi.type == PV_IDX_INT)
820
+	{
821
+		*idx = ip->pvi.u.ival;
822
+		return 0;
823
+	}
824
+
825
+	/* pvar */
826
+	if(pv_get_spec_value(msg, (pv_spec_p)ip->pvi.u.dval, &tv)!=0)
827
+	{
828
+		LM_ERR("cannot get index value\n");
829
+		return -1;
830
+	}
831
+	if(!(tv.flags&PV_VAL_INT))
832
+	{
833
+		LM_ERR("invalid index value\n");
834
+		return -1;
835
+	}
836
+	*idx = tv.ri;
837
+	return 0;
838
+}
839
+
724 840
 int pv_get_spec_value(struct sip_msg* msg, pv_spec_p sp, pv_value_t *value)
725 841
 {
726 842
 	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 737
 	ret = (*sp->getf)(msg, &(sp->pvp), value);
738 738
 	if(ret!=0)
739 739
 		return ret;
740
+		
740 741
 	if(sp->trans)
741 742
 		return tr_exec(msg, (trans_t*)sp->trans, value);
742 743
 	return ret;
... ...
@@ -814,6 +993,73 @@ done:
814 814
 	return 0;
815 815
 }
816 816
 
817
+/**
818
+ *
819
+ */
820
+pvname_list_t* parse_pvname_list(str *in, unsigned int type)
821
+{
822
+	pvname_list_t* head = NULL;
823
+	pvname_list_t* al = NULL;
824
+	pvname_list_t* last = NULL;
825
+	char *p;
826
+	pv_spec_t spec;
827
+	str s;
828
+
829
+	if(in==NULL || in->s==NULL)
830
+	{
831
+		LM_ERR("bad parameters\n");
832
+		return NULL;
833
+	}
834
+
835
+	p = in->s;
836
+	while(is_in_str(p, in))
837
+	{
838
+		while(is_in_str(p, in) && (*p==' '||*p=='\t'||*p==','||*p==';'))
839
+			p++;
840
+		if(!is_in_str(p, in))
841
+		{
842
+			if(head==NULL)
843
+				LM_ERR("wrong item name list [%.*s]\n", in->len, in->s);
844
+			return head;
845
+		}
846
+		s.s=p;
847
+		s.len = in->s+in->len-p;
848
+		p = pv_parse_spec(&s, &spec);
849
+		if(p==NULL || (type && spec.type!=type))
850
+		{
851
+			LM_ERR("wrong item name list [%.*s]!\n", in->len, in->s);
852
+			goto error;
853
+		}
854
+		al = (pvname_list_t*)pkg_malloc(sizeof(pvname_list_t));
855
+		if(al==NULL)
856
+		{
857
+			LM_ERR("no more memory!\n");
858
+			goto error;
859
+		}
860
+		memset(al, 0, sizeof(pvname_list_t));
861
+		memcpy(&al->sname, &spec, sizeof(pv_spec_t));
862
+
863
+		if(last==NULL)
864
+		{
865
+			head = al;
866
+			last = al;
867
+		} else {
868
+			last->next = al;
869
+			last = al;
870
+		}
871
+	}
872
+
873
+	return head;
874
+
875
+error:
876
+	while(head)
877
+	{
878
+		al = head;
879
+		head=head->next;
880
+		pkg_free(al);
881
+	}
882
+	return NULL;
883
+}
817 884
 
818 885
 /**
819 886
  *
... ...
@@ -853,6 +1099,23 @@ void pv_value_destroy(pv_value_t *val)
853 853
 	memset(val, 0, sizeof(pv_value_t));
854 854
 }
855 855
 
856
+#define PV_PRINT_BUF_SIZE  1024
857
+#define PV_PRINT_BUF_NO    3
858
+int pv_printf_s(struct sip_msg* msg, pv_elem_p list, str *s)
859
+{
860
+	static int buf_itr = 0;
861
+	static char buf[PV_PRINT_BUF_NO][PV_PRINT_BUF_SIZE];
862
+
863
+	if (list->next==0 && list->spec.getf==0) {
864
+		*s = list->text;
865
+		return 0;
866
+	} else {
867
+		s->s = buf[buf_itr];
868
+		s->len = PV_PRINT_BUF_SIZE;
869
+		buf_itr = (buf_itr+1)%PV_PRINT_BUF_NO;
870
+		return pv_printf( msg, list, s->s, &s->len);
871
+	}
872
+}
856 873
 
857 874
 /********************************************************
858 875
  * Transformations API
... ...
@@ -879,7 +1142,7 @@ static inline char* tr_get_class(str *in, char *p, str *tclass)
879 879
 /**
880 880
  *
881 881
  */
882
-static inline trans_t* tr_new()
882
+static inline trans_t* tr_new(void)
883 883
 {
884 884
 	trans_t *t = NULL;
885 885
 
... ...
@@ -984,6 +1247,14 @@ void tr_destroy(trans_t *t)
984 984
 	memset(t, 0, sizeof(trans_t));
985 985
 }
986 986
 
987
+/*!
988
+ * \brief Exec transformation on a pseudo-variable value
989
+ * \param msg SIP message
990
+ * \param tr one or more transformations
991
+ * \param val pseudo-variable value
992
+ * \return 0 on success, -1 on error
993
+ */
994
+
987 995
 int tr_exec(struct sip_msg *msg, trans_t *t, pv_value_t *v)
988 996
 {
989 997
 	int r;
... ...
@@ -1048,14 +1319,14 @@ typedef struct _tr_item
1048 1048
 	struct _tr_item *next;
1049 1049
 } tr_item_t, *tr_item_p;
1050 1050
 
1051
-static tr_item_t* _tr_table[PV_TABLE_SIZE];
1051
+static tr_item_t* _tr_table[TR_TABLE_SIZE];
1052 1052
 static int _tr_table_set = 0;
1053 1053
 
1054 1054
 
1055 1055
 /**
1056 1056
  *
1057 1057
  */
1058
-void tr_init_table()
1058
+void tr_init_table(void)
1059 1059
 {
1060 1060
 	memset(_tr_table, 0, sizeof(tr_item_t*)*TR_TABLE_SIZE);
1061 1061
 	_tr_table_set = 1;
... ...
@@ -1070,7 +1341,7 @@ int tr_table_add(tr_export_t *e)
1070 1070
 	tr_item_t *trj = NULL;
1071 1071
 	tr_item_t *trn = NULL;
1072 1072
 	int found;
1073
-	int trid;
1073
+	unsigned int trid;
1074 1074
 
1075 1075
 	if(e==NULL || e->tclass.s==NULL)
1076 1076
 	{
... ...
@@ -1085,9 +1356,10 @@ int tr_table_add(tr_export_t *e)
1085 1085
 	}
1086 1086
 
1087 1087
 	found = 0;
1088
-	trid = get_hash1_raw(e->tclass.s, e->tclass.len);
1088
+	// trid = get_hash1_raw(e->tclass.s, e->tclass.len);
1089
+	trid = core_hash(&e->tclass, 0, 0);
1089 1090
 
1090
-	tri = _tr_table[trid%PV_TABLE_SIZE];
1091
+	tri = _tr_table[trid%TR_TABLE_SIZE];
1091 1092
 	while(tri)
1092 1093
 	{
1093 1094
 		if(tri->trid > trid)
... ...
@@ -1120,10 +1392,12 @@ int tr_table_add(tr_export_t *e)
1120 1120
 	memcpy(&(trn->tre), e, sizeof(tr_export_t));
1121 1121
 	trn->trid = trid;
1122 1122
 
1123
+	//LM_DBG("TR class [%.*s] added to entry [%d]\n", e->tclass.len,
1124
+	//					e->tclass.s, trid%TR_TABLE_SIZE);
1123 1125
 	if(trj==0)
1124 1126
 	{
1125
-		trn->next = _tr_table[trid%PV_TABLE_SIZE];
1126
-		_tr_table[trid%PV_TABLE_SIZE] = trn;
1127
+		trn->next = _tr_table[trid%TR_TABLE_SIZE];
1128
+		_tr_table[trid%TR_TABLE_SIZE] = trn;
1127 1129
 		goto done;
1128 1130
 	}
1129 1131
 	trn->next = trj->next;
... ...
@@ -1191,7 +1465,8 @@ tr_export_t* tr_lookup_class(str *tclass)
1191 1191
 	}
1192 1192
 
1193 1193
 	/* search in TR table */
1194
-	trid = get_hash1_raw(tclass->s, tclass->len);
1194
+	// trid = get_hash1_raw(tclass->s, tclass->len);
1195
+	trid = core_hash(tclass, 0, 0);
1195 1196
 	tri = _tr_table[trid%TR_TABLE_SIZE];
1196 1197
 	while(tri)
1197 1198
 	{
... ...
@@ -1209,3 +1484,8 @@ tr_export_t* tr_lookup_class(str *tclass)
1209 1209
 	return NULL;
1210 1210
 }
1211 1211
 
1212
+void pv_api_destroy(void)
1213
+{
1214
+	/* free PV and TR hash tables */
1215
+	return;
1216
+}
... ...
@@ -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 72
 
73 73
 enum _pv_type { 
74 74
 	PVT_NONE=0,           PVT_EMPTY,             PVT_NULL, 
75
-	PVT_MARKER,           PVT_AVP,               PVT_COLOR,
75
+	PVT_MARKER,           PVT_AVP,               PVT_HDR,
76
+	PVT_RURI,             PVT_RURI_USERNAME,     PVT_RURI_DOMAIN,
77
+	PVT_DSTURI,           PVT_COLOR,             PVT_BRANCH,
78
+	PVT_FROM,             PVT_TO,                PVT_OURI,
79
+	PVT_SCRIPTVAR,        PVT_MSG_BODY,          PVT_CONTEXT,
76 80
 	PVT_OTHER,            PVT_EXTRA /* keep it last */
77 81
 };
78 82
 
... ...
@@ -161,7 +166,6 @@ typedef struct _pv_elem
161 161
 char* pv_parse_spec2(str *in, pv_spec_p sp, int silent);
162 162
 #define pv_parse_spec(in, sp) pv_parse_spec2((in), (sp), 0)
163 163
 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 164
 int pv_printf(struct sip_msg* msg, pv_elem_p list, char *buf, int *len);
166 165
 int pv_elem_free_all(pv_elem_p log);
167 166
 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 172
 		unsigned short *name_type);
173 173
 int pv_get_spec_name(struct sip_msg* msg, pv_param_p ip, pv_value_t *name);
174 174
 int pv_parse_format(str *in, pv_elem_p *el);
175
+int pv_parse_index(pv_spec_p sp, str *in);
175 176
 int pv_init_iname(pv_spec_p sp, int param);
176 177
 int pv_printf_s(struct sip_msg* msg, pv_elem_p list, str *s);
178
+void pv_api_destroy(void);
177 179
 
178 180
 typedef struct _pvname_list {
179 181
 	pv_spec_t sname;
... ...
@@ -191,10 +197,7 @@ int register_pvars_mod(char *mod_name, pv_export_t *items);
191 191
 int pv_free_extra_list(void);
192 192
 
193 193
 /*! \brief PV helper functions */
194
-int pv_parse_index(pv_spec_p sp, str *in);
195
-
196 194
 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 195
 
199 196
 int pv_get_uintval(struct sip_msg *msg, pv_param_t *param,
200 197
 		pv_value_t *res, unsigned int uival);
... ...
@@ -218,7 +221,7 @@ int pv_get_intstrval(struct sip_msg *msg, pv_param_t *param,
218 218
 #define TR_PARAM_MARKER		','
219 219
 
220 220
 enum _tr_param_type { TR_PARAM_NONE=0, TR_PARAM_STRING, TR_PARAM_NUMBER,
221
-	TR_PARAM_SPEC };
221
+	TR_PARAM_SPEC, TR_PARAM_SUBST, TR_PARAM_OTHER };
222 222
 
223 223
 typedef struct _tr_param {
224 224
 	int type;
... ...
@@ -250,6 +253,9 @@ typedef struct _tr_export {
250 250
 char* tr_lookup(str *in, trans_t **tr);
251 251
 tr_export_t* tr_lookup_class(str *tclass);
252 252
 int tr_exec(struct sip_msg *msg, trans_t *t, pv_value_t *v);
253
+void tr_param_free(tr_param_t *tp);
254
+
255
+int register_trans_mod(char *mod_name, tr_export_t *items);
253 256
 
254 257
 #endif
255 258
 
... ...
@@ -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*/