Browse code

posops: pos_rsearch() - search last occurence of a regex

Daniel-Constantin Mierla authored on 30/09/2021 06:43:08
Showing 2 changed files
... ...
@@ -376,6 +376,35 @@ $var(idx) = pos_rfindi_str("100", "kamailio");
376 376
 				<programlisting format="linespecific">
377 377
 ...
378 378
 $var(idx) = pos_search("100", "[0-9]+");
379
+...
380
+				</programlisting>
381
+			</example>
382
+		</section>
383
+		<section id="posops.f.pos_rsearch">
384
+			<title>
385
+				<function moreinfo="none">pos_rsearch(idx, re)</function>
386
+			</title>
387
+			<para>
388
+			Return the position of last match that starts matching the regular
389
+			expression re in message buffer starting at idx. In case of not
390
+			finding it or error, the return code is negative. If val is at
391
+			index 0, it returns the value specified by modparam idx0.
392
+			</para>
393
+			<para>
394
+			The idx can be an integer value or a variable holding an integer. If
395
+			the value is negative, the position is counted from the end of the buffer.
396
+			</para>
397
+			<para>
398
+			The re can be a static regular expression string.
399
+			</para>
400
+			<para>
401
+			This function can be used from ANY_ROUTE.
402
+			</para>
403
+			<example>
404
+				<title><function>pos_rsearch()</function> usage</title>
405
+				<programlisting format="linespecific">
406
+...
407
+$var(idx) = pos_rsearch("100", "[0-9]+");
379 408
 ...
380 409
 				</programlisting>
381 410
 			</example>
... ...
@@ -50,6 +50,7 @@ static int w_posops_pos_findi_str(sip_msg_t* msg, char* p1idx, char* p2val);
50 50
 static int w_posops_pos_rfind_str(sip_msg_t* msg, char* p1idx, char* p2val);
51 51
 static int w_posops_pos_rfindi_str(sip_msg_t* msg, char* p1idx, char* p2val);
52 52
 static int w_posops_pos_search(sip_msg_t* msg, char* p1idx, char* p2re);
53
+static int w_posops_pos_rsearch(sip_msg_t* msg, char* p1idx, char* p2re);
53 54
 
54 55
 typedef struct posops_data {
55 56
 	int ret;
... ...
@@ -100,6 +101,8 @@ static cmd_export_t cmds[]={
100 101
 		fixup_free_igp_spve, ANY_ROUTE},
101 102
 	{"pos_search",    (cmd_function)w_posops_pos_search, 2, fixup_igp_regexp,
102 103
 		fixup_free_igp_regexp, ANY_ROUTE},
104
+	{"pos_rsearch",    (cmd_function)w_posops_pos_rsearch, 2, fixup_igp_regexp,
105
+		fixup_free_igp_regexp, ANY_ROUTE},
103 106
 
104 107
 	{0, 0, 0, 0, 0, 0}
105 108
 };
... ...
@@ -688,6 +691,9 @@ static int ki_posops_pos_search_helper(sip_msg_t *msg, int idx, regex_t *re)
688 691
 	return _posops_data.ret;
689 692
 }
690 693
 
694
+/**
695
+ *
696
+ */
691 697
 static int ki_posops_pos_search(sip_msg_t* msg, int idx, str* sre)
692 698
 {
693 699
 	regex_t mre;
... ...
@@ -725,6 +731,79 @@ static int w_posops_pos_search(sip_msg_t* msg, char* p1idx, char* p2re)
725 731
 	return ki_posops_pos_search_helper(msg, idx, re);
726 732
 }
727 733
 
734
+/**
735
+ *
736
+ */
737
+static int ki_posops_pos_rsearch_helper(sip_msg_t *msg, int idx, regex_t *re)
738
+{
739
+	regmatch_t pmatch;
740
+	int i;
741
+	int ret = -1;
742
+
743
+	if(idx<0) {
744
+		idx += msg->len;
745
+	}
746
+	if(idx<0 || idx >= msg->len) {
747
+		return -1;
748
+	}
749
+
750
+	for(i=msg->len-1; i>=idx; i--) {
751
+		ret = regexec(re, msg->buf + i, 1, &pmatch, 0);
752
+		if(ret==0) {
753
+			break;
754
+		}
755
+	}
756
+	if (ret!=0) {
757
+		return -1;
758
+	}
759
+
760
+	_posops_data.idx = (int)(msg->buf + i + pmatch.rm_so);
761
+	_posops_data.ret = (_posops_data.idx==0)?posops_idx0:_posops_data.idx;
762
+	_posops_data.len = pmatch.rm_eo-pmatch.rm_so;
763
+
764
+	return _posops_data.ret;
765
+}
766
+
767
+/**
768
+ *
769
+ */
770
+static int ki_posops_pos_rsearch(sip_msg_t* msg, int idx, str* sre)
771
+{
772
+	regex_t mre;
773
+	int ret;
774
+
775
+	posops_data_init();
776
+	memset(&mre, 0, sizeof(regex_t));
777
+	if (regcomp(&mre, sre->s, REG_EXTENDED|REG_ICASE|REG_NEWLINE)!=0) {
778
+		LM_ERR("failed to compile regex: %.*s\n", sre->len, sre->s);
779
+		return -1;
780
+	}
781
+
782
+	ret = ki_posops_pos_rsearch_helper(msg, idx, &mre);
783
+
784
+	regfree(&mre);
785
+
786
+	return ret;
787
+}
788
+
789
+/**
790
+ *
791
+ */
792
+static int w_posops_pos_rsearch(sip_msg_t* msg, char* p1idx, char* p2re)
793
+{
794
+	int idx = 0;
795
+	regex_t *re = NULL;
796
+
797
+	posops_data_init();
798
+	if(fixup_get_ivalue(msg, (gparam_t*)p1idx, &idx)!=0) {
799
+		LM_ERR("unable to get idx parameter\n");
800
+		return -1;
801
+	}
802
+	re = (regex_t*)p2re;
803
+
804
+	return ki_posops_pos_rsearch_helper(msg, idx, re);
805
+}
806
+
728 807
 /**
729 808
  *
730 809
  */
... ...
@@ -836,6 +915,11 @@ static sr_kemi_t sr_kemi_posops_exports[] = {
836 915
 		{ SR_KEMIP_INT, SR_KEMIP_STR, SR_KEMIP_NONE,
837 916
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
838 917
 	},
918
+	{ str_init("posops"), str_init("pos_rsearch"),
919
+		SR_KEMIP_INT, ki_posops_pos_rsearch,
920
+		{ SR_KEMIP_INT, SR_KEMIP_STR, SR_KEMIP_NONE,
921
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
922
+	},
839 923
 
840 924
 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
841 925
 };