Add CBS topic range functions
authorDenis Kenzior <denis.kenzior@intel.com>
Wed, 9 Sep 2009 19:28:20 +0000 (14:28 -0500)
committerDenis Kenzior <denkenz@gmail.com>
Thu, 10 Sep 2009 21:13:15 +0000 (16:13 -0500)
src/smsutil.c
src/smsutil.h

index 76095af..4e7d9f0 100644 (file)
@@ -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;
+}
index daccaf7..a60b95d 100644 (file)
@@ -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);