s/DUMP/DUMPVAL/.
[ttfautohint.git] / lib / numberset.c
blob0f3ab21b46ea87b65f9112ade2e1e7c605e6474c
1 /* numberset.c */
3 /*
4 * Copyright (C) 2012 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <limits.h>
22 #include "numberset.h"
25 const char*
26 number_set_parse(const char* s,
27 number_range** number_set,
28 int min,
29 int max)
31 number_range* cur = NULL;
32 number_range* new_range;
33 number_range* tmp;
35 const char* last_pos = s;
36 int last_end = -1;
37 int t;
38 number_range* error_code = NULL;
41 if (min < 0)
42 min = 0;
43 if (max < 0)
44 max = INT_MAX;
45 if (min > max)
47 t = min;
48 min = max;
49 max = t;
52 for (;;)
54 int digit;
55 int n = -1;
56 int m = -1;
59 while (isspace(*s))
60 s++;
62 if (*s == ',')
64 s++;
65 continue;
67 else if (*s == '-')
69 last_pos = s;
70 n = min;
72 else if (isdigit(*s))
74 last_pos = s;
75 n = 0;
78 digit = *s - '0';
79 if (n > INT_MAX / 10
80 || (n == INT_MAX / 10 && digit > 5))
82 error_code = NUMBERSET_OVERFLOW;
83 break;
86 n = n * 10 + digit;
87 s++;
88 } while (isdigit(*s));
90 while (isspace(*s))
91 s++;
93 else if (*s == '\0')
94 break; /* end of data */
95 else
97 error_code = NUMBERSET_INVALID_CHARACTER;
98 break;
101 if (*s == '-')
103 s++;
105 while (isspace(*s))
106 s++;
108 if (isdigit(*s))
110 m = 0;
113 digit = *s - '0';
114 if (m > INT_MAX / 10
115 || (m == INT_MAX / 10 && digit > 5))
117 error_code = NUMBERSET_OVERFLOW;
118 break;
121 m = m * 10 + digit;
122 s++;
123 } while (isdigit(*s));
126 else
127 m = n;
129 if (m == -1)
130 m = max;
132 if (m < n)
134 t = n;
135 n = m;
136 m = t;
139 if (n < min || m > max)
141 error_code = NUMBERSET_INVALID_RANGE;
142 break;
145 if (last_end >= n)
147 error_code = NUMBERSET_OVERLAPPING_RANGES;
148 break;
151 if (cur
152 && last_end + 1 == n)
154 /* merge adjacent ranges */
155 cur->end = m;
157 else
159 if (number_set)
161 new_range = (number_range*)malloc(sizeof (number_range));
162 if (!new_range)
164 error_code = NUMBERSET_ALLOCATION_ERROR;
165 break;
168 /* prepend new range to list */
169 new_range->start = n;
170 new_range->end = m;
171 new_range->next = cur;
172 cur = new_range;
175 last_end = m;
177 } /* end of loop */
179 if (error_code)
181 /* deallocate data */
182 while (cur)
184 tmp = cur;
185 cur = cur->next;
186 free(tmp);
189 s = last_pos;
190 if (number_set)
191 *number_set = error_code;
193 else
195 /* success; now reverse list to have elements in ascending order */
196 number_range* list = NULL;
199 while (cur)
201 tmp = cur;
202 cur = cur->next;
203 tmp->next = list;
204 list = tmp;
207 if (number_set)
208 *number_set = list;
211 return s;
215 void
216 number_set_free(number_range* number_set)
218 number_range* nr = number_set;
219 number_range* tmp;
222 while (nr)
224 tmp = nr;
225 nr = nr->next;
226 free(tmp);
231 char*
232 number_set_show(number_range* number_set,
233 int min,
234 int max)
236 char* s;
237 char* s_new;
238 size_t s_len;
239 size_t s_len_new;
241 number_range* nr = number_set;
243 char tmp[256];
244 int tmp_len;
245 int t;
246 const char *comma;
249 if (min < 0)
250 min = 0;
251 if (max < 0)
252 max = INT_MAX;
253 if (min > max)
255 t = min;
256 min = max;
257 max = t;
260 /* we return an empty string for an empty number set */
261 /* (this is, number_set == NULL or unsuitable `min' and `max' values) */
262 s = (char*)malloc(1);
263 if (!s)
264 return NULL;
265 *s = '\0';
267 s_len = 1;
269 while (nr)
271 if (nr->start > max)
272 return s;
273 if (nr->end < min)
274 goto Again;
276 comma = (s_len == 1) ? "" : ", ";
278 if (nr->start <= min
279 && nr->end >= max)
280 tmp_len = sprintf(tmp, "-");
281 else if (nr->start <= min)
282 tmp_len = sprintf(tmp, "-%i",
283 nr->end);
284 else if (nr->end >= max)
285 tmp_len = sprintf(tmp, "%s%i-",
286 comma, nr->start);
287 else
289 if (nr->start == nr->end)
290 tmp_len = sprintf(tmp, "%s%i",
291 comma, nr->start);
292 else
293 tmp_len = sprintf(tmp, "%s%i-%i",
294 comma, nr->start, nr->end);
297 s_len_new = s_len + tmp_len;
298 s_new = (char*)realloc(s, s_len_new);
299 if (!s_new)
301 free(s);
302 return NULL;
304 strcpy(s_new + s_len - 1, tmp);
305 s_len = s_len_new;
306 s = s_new;
308 Again:
309 nr = nr->next;
312 return s;
317 number_set_is_element(number_range* number_set,
318 int number)
320 number_range* nr = number_set;
323 while (nr)
325 if (number < nr->start)
326 return 0;
327 if (nr->start <= number
328 && number <= nr->end)
329 return 1;
330 nr = nr->next;
333 return 0;
336 /* end of numberset.c */