void rangelist_remove_range(struct RangeList *task, unsigned begin, unsigned end) { unsigned i; struct Range x; x.begin = begin; x.end = end; /* See if the range overlaps any exist range already in the * list */ for (i = 0; i < task->count; i++) { if (!range_is_overlap(task->list[i], x)) continue; /* If the removal-range wholly covers the range, delete * it completely */ if (begin <= task->list[i].begin && end >= task->list[i].end) { todo_remove_at(task, i); i--; continue; } /* If the removal-range bisects the target-rage, truncate * the lower end and add a new high-end */ if (begin > task->list[i].begin && end < task->list[i].end) { struct Range newrange; newrange.begin = end+1; newrange.end = task->list[i].end; task->list[i].end = begin-1; rangelist_add_range(task, newrange.begin, newrange.end); i--; continue; } /* If overlap on the lower side */ if (end >= task->list[i].begin && end < task->list[i].end) { task->list[i].begin = end+1; } /* If overlap on the upper side */ if (begin > task->list[i].begin && begin <= task->list[i].end) { task->list[i].end = begin-1; } //assert(!"impossible"); } }
/*************************************************************************** * Add the IPv4 range to our list of ranges. ***************************************************************************/ void rangelist_add_range(struct RangeList *task, unsigned begin, unsigned end) { unsigned i; struct Range range; range.begin = begin; range.end = end; /* auto-expand the list if necessary */ if (task->count + 1 >= task->max) { size_t new_max = (size_t)task->max * 2 + 1; struct Range *new_list; if (new_max >= SIZE_MAX/sizeof(*new_list)) exit(1); /* integer overflow */ new_list = (struct Range *)malloc(sizeof(*new_list) * new_max); if (new_list == NULL) exit(1); /* out of memory */ memcpy(new_list, task->list, task->count * sizeof(*new_list)); if (task->list) free(task->list); task->list = new_list; task->max = (unsigned)new_max; } /* See if the range overlaps any exist range already in the * list */ for (i = 0; i < task->count; i++) { if (range_is_overlap(task->list[i], range)) { range_combine(&range, task->list[i]); todo_remove_at(task, i); rangelist_add_range(task, range.begin, range.end); return; } } /* Find a spot to insert in sorted order */ for (i = 0; i < task->count; i++) { if (range.begin < task->list[i].begin) { memmove(task->list+i+1, task->list+i, (task->count - i) * sizeof(task->list[0])); break; } } /* Add to end of list */ task->list[i].begin = begin; task->list[i].end = end; task->count++; }
/*************************************************************************** * Add the IPv4 range to our list of ranges. ***************************************************************************/ void rangelist_add_range(struct RangeList *task, unsigned begin, unsigned end) { int first, middle, last; struct Range range; range.begin = begin; range.end = end; /* auto-expand the list if necessary */ if (task->count + 1 >= task->max) { size_t new_max = (size_t)task->max * 2 + 1; struct Range *new_list; if (new_max >= SIZE_MAX/sizeof(*new_list)) exit(1); /* integer overflow */ new_list = (struct Range *)malloc(sizeof(*new_list) * new_max); if (new_list == NULL) exit(1); /* out of memory */ memcpy(new_list, task->list, task->count * sizeof(*new_list)); if (task->list) free(task->list); task->list = new_list; task->max = (unsigned)new_max; } if (!task->count) { task->list[0].begin = begin; task->list[0].end = end; task->count++; return; } /* Binary search to find where the current IP range belongs by comparing range beginnings */ first = 0; last = task->count - 1; middle = (first + last) / 2; while (first <= last) { if (task->list[middle].begin < range.begin) first = middle + 1; else if (task->list[middle].begin == range.begin) break; else last = middle - 1; middle = (first + last) / 2; } /* `middle` now points to the IP range numerically smaller than or equal to it. Try to merge it * with the numerically smaller, and then greater ranges. */ if (range_is_overlap(task->list[middle], range)) { range_combine(&range, task->list[middle]); todo_remove_at(task, middle); rangelist_add_range(task, range.begin, range.end); return; } if (task->count > (middle+1) && range_is_overlap(task->list[middle+1], range)) { range_combine(&range, task->list[middle+1]); todo_remove_at(task, middle+1); rangelist_add_range(task, range.begin, range.end); return; } /* Make space for the current range respecting sorted order by placing it in entry `middle+1` */ memmove(task->list+middle+2, task->list+middle+1, (task->count - middle - 1) * sizeof(task->list[0])); /* Add to the list */ task->list[middle+1].begin = begin; task->list[middle+1].end = end; task->count++; }