summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDenis Kenzior <denis.kenzior@intel.com>2009-09-09 14:28:20 -0500
committerDenis Kenzior <denkenz@gmail.com>2009-09-10 16:13:15 -0500
commit52d3c235d5233ca67bbc0c8c621102905f60c379 (patch)
tree832d3bc1db5bb08d4f0f52c6f529747ec0b26cdf /src
parent94a0c4e708df2f7b3596eb127549ec8bf23bfc79 (diff)
downloadofono-52d3c235d5233ca67bbc0c8c621102905f60c379.tar.bz2
Add CBS topic range functions
Diffstat (limited to 'src')
-rw-r--r--src/smsutil.c212
-rw-r--r--src/smsutil.h8
2 files changed, 220 insertions, 0 deletions
diff --git a/src/smsutil.c b/src/smsutil.c
index 76095aff..4e7d9f07 100644
--- a/src/smsutil.c
+++ b/src/smsutil.c
@@ -3436,3 +3436,215 @@ out:
return completed;
}
+
+static inline int skip_to_next_field(const char *str, int pos, int len)
+{
+ if (pos < len && str[pos] == ',')
+ pos += 1;
+
+ while (pos < len && str[pos] == ' ')
+ pos += 1;
+
+ return pos;
+}
+
+static gboolean next_range(const char *str, int *offset, gint *min, gint *max)
+{
+ int pos;
+ int end;
+ int len;
+ int low = 0;
+ int high = 0;
+
+ len = strlen(str);
+
+ pos = *offset;
+
+ while (pos < len && str[pos] == ' ')
+ pos += 1;
+
+ end = pos;
+
+ while (str[end] >= '0' && str[end] <= '9') {
+ low = low * 10 + (int)(str[end] - '0');
+ end += 1;
+ }
+
+ if (pos == end)
+ return FALSE;
+
+ if (str[end] != '-') {
+ high = low;
+ goto out;
+ }
+
+ pos = end = end + 1;
+
+ while (str[end] >= '0' && str[end] <= '9') {
+ high = high * 10 + (int)(str[end] - '0');
+ end += 1;
+ }
+
+ if (pos == end)
+ return FALSE;
+
+out:
+ *offset = skip_to_next_field(str, end, len);
+
+ if (min)
+ *min = low;
+
+ if (max)
+ *max = high;
+
+ return TRUE;
+}
+
+static GSList *cbs_optimize_ranges(GSList *ranges)
+{
+ struct cbs_topic_range *range;
+ unsigned char bitmap[125];
+ GSList *l;
+ unsigned short i;
+ GSList *ret = NULL;
+
+ memset(bitmap, 0, sizeof(bitmap));
+
+ for (l = ranges; l; l = l->next) {
+ range = l->data;
+
+ for (i = range->min; i <= range->max; i++) {
+ int byte_offset = i / 8;
+ int bit = i % 8;
+
+ bitmap[byte_offset] |= 1 << bit;
+ }
+ }
+
+ range = NULL;
+
+ for (i = 0; i <= 999; i++) {
+ int byte_offset = i / 8;
+ int bit = i % 8;
+
+ if (is_bit_set(bitmap[byte_offset], bit) == FALSE) {
+ if (range) {
+ ret = g_slist_prepend(ret, range);
+ range = NULL;
+ }
+
+ continue;
+ }
+
+ if (range) {
+ range->max = i;
+ continue;
+ }
+
+ range = g_new0(struct cbs_topic_range, 1);
+ range->min = i;
+ range->max = i;
+ }
+
+ if (range != NULL)
+ ret = g_slist_prepend(ret, range);
+
+ ret = g_slist_reverse(ret);
+
+ return ret;
+}
+
+GSList *cbs_extract_topic_ranges(const char *ranges)
+{
+ int min;
+ int max;
+ int offset = 0;
+ GSList *ret = NULL;
+ GSList *tmp;
+
+ while (next_range(ranges, &offset, &min, &max) == TRUE) {
+ if (min < 0 || min > 999)
+ return NULL;
+
+ if (max < 0 || max > 999)
+ return NULL;
+
+ if (max < min)
+ return NULL;
+ }
+
+ if (ranges[offset] != '\0')
+ return NULL;
+
+ offset = 0;
+
+ while (next_range(ranges, &offset, &min, &max) == TRUE) {
+ struct cbs_topic_range *range = g_new0(struct cbs_topic_range, 1);
+
+ range->min = min;
+ range->max = max;
+
+ ret = g_slist_prepend(ret, range);
+ }
+
+ tmp = cbs_optimize_ranges(ret);
+ g_slist_foreach(ret, (GFunc)g_free, NULL);
+ g_slist_free(ret);
+
+ return tmp;
+}
+
+static inline int element_length(unsigned short element)
+{
+ if (element <= 9)
+ return 1;
+
+ if (element <= 99)
+ return 2;
+
+ return 3;
+}
+
+static inline int range_length(struct cbs_topic_range *range)
+{
+ if (range->min == range->max)
+ return element_length(range->min);
+
+ return element_length(range->min) + element_length(range->max) + 1;
+}
+
+char *cbs_topic_ranges_to_string(GSList *ranges)
+{
+ int len = 0;
+ int nelem = 0;
+ struct cbs_topic_range *range;
+ GSList *l;
+ char *ret;
+
+ for (l = ranges; l; l = l->next) {
+ range = l->data;
+
+ len += range_length(range);
+ nelem += 1;
+ }
+
+ /* Space for ranges, commas and terminator null */
+ ret = g_new(char, len + nelem);
+
+ len = 0;
+
+ for (l = ranges; l; l = l->next) {
+ range = l->data;
+
+ if (range->min != range->max)
+ len += sprintf(ret + len, "%hu-%hu",
+ range->min, range->max);
+ else
+ len += sprintf(ret + len, "%hu", range->min);
+
+ if (l->next != NULL)
+ ret[len++] = ',';
+ }
+
+ return ret;
+}
diff --git a/src/smsutil.h b/src/smsutil.h
index daccaf71..a60b95d2 100644
--- a/src/smsutil.h
+++ b/src/smsutil.h
@@ -388,6 +388,11 @@ struct cbs_assembly {
GSList *recv_cell;
};
+struct cbs_topic_range {
+ unsigned short min;
+ unsigned short max;
+};
+
static inline gboolean is_bit_set(unsigned char oct, int bit)
{
int mask = 0x1 << bit;
@@ -485,3 +490,6 @@ GSList *cbs_assembly_add_page(struct cbs_assembly *assembly,
const struct cbs *cbs);
void cbs_assembly_location_changed(struct cbs_assembly *assembly,
gboolean lac, gboolean ci);
+
+char *cbs_topic_ranges_to_string(GSList *ranges);
+GSList *cbs_extract_topic_ranges(const char *ranges);