Line data Source code
1 : /*
2 : * wpa_supplicant/hostapd / common helper functions, etc.
3 : * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
4 : *
5 : * This software may be distributed under the terms of the BSD license.
6 : * See README for more details.
7 : */
8 :
9 : #include "includes.h"
10 :
11 : #include "common.h"
12 :
13 :
14 169863 : static int hex2num(char c)
15 : {
16 169863 : if (c >= '0' && c <= '9')
17 143345 : return c - '0';
18 26518 : if (c >= 'a' && c <= 'f')
19 20650 : return c - 'a' + 10;
20 5868 : if (c >= 'A' && c <= 'F')
21 5801 : return c - 'A' + 10;
22 67 : return -1;
23 : }
24 :
25 :
26 63783 : int hex2byte(const char *hex)
27 : {
28 : int a, b;
29 63783 : a = hex2num(*hex++);
30 63783 : if (a < 0)
31 16 : return -1;
32 63767 : b = hex2num(*hex++);
33 63767 : if (b < 0)
34 23 : return -1;
35 63744 : return (a << 4) | b;
36 : }
37 :
38 :
39 : /**
40 : * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
41 : * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
42 : * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
43 : * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
44 : */
45 1548 : int hwaddr_aton(const char *txt, u8 *addr)
46 : {
47 : int i;
48 :
49 10660 : for (i = 0; i < 6; i++) {
50 : int a, b;
51 :
52 9160 : a = hex2num(*txt++);
53 9160 : if (a < 0)
54 21 : return -1;
55 9139 : b = hex2num(*txt++);
56 9139 : if (b < 0)
57 4 : return -1;
58 9135 : *addr++ = (a << 4) | b;
59 9135 : if (i < 5 && *txt++ != ':')
60 23 : return -1;
61 : }
62 :
63 1500 : return 0;
64 : }
65 :
66 : /**
67 : * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
68 : * @txt: MAC address as a string (e.g., "001122334455")
69 : * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
70 : * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
71 : */
72 0 : int hwaddr_compact_aton(const char *txt, u8 *addr)
73 : {
74 : int i;
75 :
76 0 : for (i = 0; i < 6; i++) {
77 : int a, b;
78 :
79 0 : a = hex2num(*txt++);
80 0 : if (a < 0)
81 0 : return -1;
82 0 : b = hex2num(*txt++);
83 0 : if (b < 0)
84 0 : return -1;
85 0 : *addr++ = (a << 4) | b;
86 : }
87 :
88 0 : return 0;
89 : }
90 :
91 : /**
92 : * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format)
93 : * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455)
94 : * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
95 : * Returns: Characters used (> 0) on success, -1 on failure
96 : */
97 2003 : int hwaddr_aton2(const char *txt, u8 *addr)
98 : {
99 : int i;
100 2003 : const char *pos = txt;
101 :
102 14008 : for (i = 0; i < 6; i++) {
103 : int a, b;
104 :
105 34010 : while (*pos == ':' || *pos == '.' || *pos == '-')
106 9994 : pos++;
107 :
108 12008 : a = hex2num(*pos++);
109 12008 : if (a < 0)
110 2 : return -1;
111 12006 : b = hex2num(*pos++);
112 12006 : if (b < 0)
113 1 : return -1;
114 12005 : *addr++ = (a << 4) | b;
115 : }
116 :
117 2000 : return pos - txt;
118 : }
119 :
120 :
121 : /**
122 : * hexstr2bin - Convert ASCII hex string into binary data
123 : * @hex: ASCII hex string (e.g., "01ab")
124 : * @buf: Buffer for the binary data
125 : * @len: Length of the text to convert in bytes (of buf); hex will be double
126 : * this size
127 : * Returns: 0 on success, -1 on failure (invalid hex string)
128 : */
129 3823 : int hexstr2bin(const char *hex, u8 *buf, size_t len)
130 : {
131 : size_t i;
132 : int a;
133 3823 : const char *ipos = hex;
134 3823 : u8 *opos = buf;
135 :
136 67513 : for (i = 0; i < len; i++) {
137 63729 : a = hex2byte(ipos);
138 63729 : if (a < 0)
139 39 : return -1;
140 63690 : *opos++ = a;
141 63690 : ipos += 2;
142 : }
143 3784 : return 0;
144 : }
145 :
146 :
147 : /**
148 : * inc_byte_array - Increment arbitrary length byte array by one
149 : * @counter: Pointer to byte array
150 : * @len: Length of the counter in bytes
151 : *
152 : * This function increments the last byte of the counter by one and continues
153 : * rolling over to more significant bytes if the byte was incremented from
154 : * 0xff to 0x00.
155 : */
156 2522 : void inc_byte_array(u8 *counter, size_t len)
157 : {
158 2522 : int pos = len - 1;
159 5045 : while (pos >= 0) {
160 2523 : counter[pos]++;
161 2523 : if (counter[pos] != 0)
162 2522 : break;
163 1 : pos--;
164 : }
165 2522 : }
166 :
167 :
168 2088 : void wpa_get_ntp_timestamp(u8 *buf)
169 : {
170 : struct os_time now;
171 : u32 sec, usec;
172 : be32 tmp;
173 :
174 : /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
175 2088 : os_get_time(&now);
176 2088 : sec = now.sec + 2208988800U; /* Epoch to 1900 */
177 : /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
178 2088 : usec = now.usec;
179 2088 : usec = 4295 * usec - (usec >> 5) - (usec >> 9);
180 2088 : tmp = host_to_be32(sec);
181 2088 : os_memcpy(buf, (u8 *) &tmp, 4);
182 2088 : tmp = host_to_be32(usec);
183 2088 : os_memcpy(buf + 4, (u8 *) &tmp, 4);
184 2088 : }
185 :
186 :
187 37514 : static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
188 : size_t len, int uppercase)
189 : {
190 : size_t i;
191 37514 : char *pos = buf, *end = buf + buf_size;
192 : int ret;
193 37514 : if (buf_size == 0)
194 0 : return 0;
195 1283606 : for (i = 0; i < len; i++) {
196 1246092 : ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
197 1246092 : data[i]);
198 1246092 : if (ret < 0 || ret >= end - pos) {
199 0 : end[-1] = '\0';
200 0 : return pos - buf;
201 : }
202 1246092 : pos += ret;
203 : }
204 37514 : end[-1] = '\0';
205 37514 : return pos - buf;
206 : }
207 :
208 : /**
209 : * wpa_snprintf_hex - Print data as a hex string into a buffer
210 : * @buf: Memory area to use as the output buffer
211 : * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
212 : * @data: Data to be printed
213 : * @len: Length of data in bytes
214 : * Returns: Number of bytes written
215 : */
216 37293 : int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
217 : {
218 37293 : return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
219 : }
220 :
221 :
222 : /**
223 : * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
224 : * @buf: Memory area to use as the output buffer
225 : * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
226 : * @data: Data to be printed
227 : * @len: Length of data in bytes
228 : * Returns: Number of bytes written
229 : */
230 221 : int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
231 : size_t len)
232 : {
233 221 : return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
234 : }
235 :
236 :
237 : #ifdef CONFIG_ANSI_C_EXTRA
238 :
239 : #ifdef _WIN32_WCE
240 : void perror(const char *s)
241 : {
242 : wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
243 : s, (int) GetLastError());
244 : }
245 : #endif /* _WIN32_WCE */
246 :
247 :
248 : int optind = 1;
249 : int optopt;
250 : char *optarg;
251 :
252 : int getopt(int argc, char *const argv[], const char *optstring)
253 : {
254 : static int optchr = 1;
255 : char *cp;
256 :
257 : if (optchr == 1) {
258 : if (optind >= argc) {
259 : /* all arguments processed */
260 : return EOF;
261 : }
262 :
263 : if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
264 : /* no option characters */
265 : return EOF;
266 : }
267 : }
268 :
269 : if (os_strcmp(argv[optind], "--") == 0) {
270 : /* no more options */
271 : optind++;
272 : return EOF;
273 : }
274 :
275 : optopt = argv[optind][optchr];
276 : cp = os_strchr(optstring, optopt);
277 : if (cp == NULL || optopt == ':') {
278 : if (argv[optind][++optchr] == '\0') {
279 : optchr = 1;
280 : optind++;
281 : }
282 : return '?';
283 : }
284 :
285 : if (cp[1] == ':') {
286 : /* Argument required */
287 : optchr = 1;
288 : if (argv[optind][optchr + 1]) {
289 : /* No space between option and argument */
290 : optarg = &argv[optind++][optchr + 1];
291 : } else if (++optind >= argc) {
292 : /* option requires an argument */
293 : return '?';
294 : } else {
295 : /* Argument in the next argv */
296 : optarg = argv[optind++];
297 : }
298 : } else {
299 : /* No argument */
300 : if (argv[optind][++optchr] == '\0') {
301 : optchr = 1;
302 : optind++;
303 : }
304 : optarg = NULL;
305 : }
306 : return *cp;
307 : }
308 : #endif /* CONFIG_ANSI_C_EXTRA */
309 :
310 :
311 : #ifdef CONFIG_NATIVE_WINDOWS
312 : /**
313 : * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
314 : * @str: Pointer to string to convert
315 : *
316 : * This function converts a unicode string to ASCII using the same
317 : * buffer for output. If UNICODE is not set, the buffer is not
318 : * modified.
319 : */
320 : void wpa_unicode2ascii_inplace(TCHAR *str)
321 : {
322 : #ifdef UNICODE
323 : char *dst = (char *) str;
324 : while (*str)
325 : *dst++ = (char) *str++;
326 : *dst = '\0';
327 : #endif /* UNICODE */
328 : }
329 :
330 :
331 : TCHAR * wpa_strdup_tchar(const char *str)
332 : {
333 : #ifdef UNICODE
334 : TCHAR *buf;
335 : buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
336 : if (buf == NULL)
337 : return NULL;
338 : wsprintf(buf, L"%S", str);
339 : return buf;
340 : #else /* UNICODE */
341 : return os_strdup(str);
342 : #endif /* UNICODE */
343 : }
344 : #endif /* CONFIG_NATIVE_WINDOWS */
345 :
346 :
347 83780 : void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
348 : {
349 83780 : char *end = txt + maxlen;
350 : size_t i;
351 :
352 1604132 : for (i = 0; i < len; i++) {
353 1520353 : if (txt + 4 > end)
354 1 : break;
355 :
356 1520352 : switch (data[i]) {
357 : case '\"':
358 1 : *txt++ = '\\';
359 1 : *txt++ = '\"';
360 1 : break;
361 : case '\\':
362 35 : *txt++ = '\\';
363 35 : *txt++ = '\\';
364 35 : break;
365 : case '\e':
366 1 : *txt++ = '\\';
367 1 : *txt++ = 'e';
368 1 : break;
369 : case '\n':
370 25 : *txt++ = '\\';
371 25 : *txt++ = 'n';
372 25 : break;
373 : case '\r':
374 1 : *txt++ = '\\';
375 1 : *txt++ = 'r';
376 1 : break;
377 : case '\t':
378 1 : *txt++ = '\\';
379 1 : *txt++ = 't';
380 1 : break;
381 : default:
382 1520288 : if (data[i] >= 32 && data[i] <= 127) {
383 1468970 : *txt++ = data[i];
384 : } else {
385 51318 : txt += os_snprintf(txt, end - txt, "\\x%02x",
386 51318 : data[i]);
387 : }
388 1520288 : break;
389 : }
390 : }
391 :
392 83780 : *txt = '\0';
393 83780 : }
394 :
395 :
396 19 : size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
397 : {
398 19 : const char *pos = str;
399 19 : size_t len = 0;
400 : int val;
401 :
402 211 : while (*pos) {
403 173 : if (len + 1 >= maxlen)
404 0 : break;
405 173 : switch (*pos) {
406 : case '\\':
407 88 : pos++;
408 88 : switch (*pos) {
409 : case '\\':
410 2 : buf[len++] = '\\';
411 2 : pos++;
412 2 : break;
413 : case '"':
414 2 : buf[len++] = '"';
415 2 : pos++;
416 2 : break;
417 : case 'n':
418 8 : buf[len++] = '\n';
419 8 : pos++;
420 8 : break;
421 : case 'r':
422 2 : buf[len++] = '\r';
423 2 : pos++;
424 2 : break;
425 : case 't':
426 2 : buf[len++] = '\t';
427 2 : pos++;
428 2 : break;
429 : case 'e':
430 2 : buf[len++] = '\e';
431 2 : pos++;
432 2 : break;
433 : case 'x':
434 54 : pos++;
435 54 : val = hex2byte(pos);
436 54 : if (val < 0) {
437 0 : val = hex2num(*pos);
438 0 : if (val < 0)
439 0 : break;
440 0 : buf[len++] = val;
441 0 : pos++;
442 : } else {
443 54 : buf[len++] = val;
444 54 : pos += 2;
445 : }
446 54 : break;
447 : case '0':
448 : case '1':
449 : case '2':
450 : case '3':
451 : case '4':
452 : case '5':
453 : case '6':
454 : case '7':
455 16 : val = *pos++ - '0';
456 16 : if (*pos >= '0' && *pos <= '7')
457 13 : val = val * 8 + (*pos++ - '0');
458 16 : if (*pos >= '0' && *pos <= '7')
459 13 : val = val * 8 + (*pos++ - '0');
460 16 : buf[len++] = val;
461 16 : break;
462 : default:
463 0 : break;
464 : }
465 88 : break;
466 : default:
467 85 : buf[len++] = *pos++;
468 85 : break;
469 : }
470 : }
471 19 : if (maxlen > len)
472 19 : buf[len] = '\0';
473 :
474 19 : return len;
475 : }
476 :
477 :
478 : /**
479 : * wpa_ssid_txt - Convert SSID to a printable string
480 : * @ssid: SSID (32-octet string)
481 : * @ssid_len: Length of ssid in octets
482 : * Returns: Pointer to a printable string
483 : *
484 : * This function can be used to convert SSIDs into printable form. In most
485 : * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
486 : * does not limit the used character set, so anything could be used in an SSID.
487 : *
488 : * This function uses a static buffer, so only one call can be used at the
489 : * time, i.e., this is not re-entrant and the returned buffer must be used
490 : * before calling this again.
491 : */
492 12776 : const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
493 : {
494 : static char ssid_txt[32 * 4 + 1];
495 :
496 12776 : if (ssid == NULL) {
497 1 : ssid_txt[0] = '\0';
498 1 : return ssid_txt;
499 : }
500 :
501 12775 : printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
502 12775 : return ssid_txt;
503 : }
504 :
505 :
506 7771 : void * __hide_aliasing_typecast(void *foo)
507 : {
508 7771 : return foo;
509 : }
510 :
511 :
512 2533 : char * wpa_config_parse_string(const char *value, size_t *len)
513 : {
514 2533 : if (*value == '"') {
515 : const char *pos;
516 : char *str;
517 2414 : value++;
518 2414 : pos = os_strrchr(value, '"');
519 2414 : if (pos == NULL || pos[1] != '\0')
520 2 : return NULL;
521 2412 : *len = pos - value;
522 2412 : str = dup_binstr(value, *len);
523 2412 : if (str == NULL)
524 0 : return NULL;
525 2412 : return str;
526 119 : } else if (*value == 'P' && value[1] == '"') {
527 : const char *pos;
528 : char *tstr, *str;
529 : size_t tlen;
530 8 : value += 2;
531 8 : pos = os_strrchr(value, '"');
532 8 : if (pos == NULL || pos[1] != '\0')
533 3 : return NULL;
534 5 : tlen = pos - value;
535 5 : tstr = dup_binstr(value, tlen);
536 5 : if (tstr == NULL)
537 0 : return NULL;
538 :
539 5 : str = os_malloc(tlen + 1);
540 5 : if (str == NULL) {
541 0 : os_free(tstr);
542 0 : return NULL;
543 : }
544 :
545 5 : *len = printf_decode((u8 *) str, tlen + 1, tstr);
546 5 : os_free(tstr);
547 :
548 5 : return str;
549 : } else {
550 : u8 *str;
551 111 : size_t tlen, hlen = os_strlen(value);
552 111 : if (hlen & 1)
553 3 : return NULL;
554 108 : tlen = hlen / 2;
555 108 : str = os_malloc(tlen + 1);
556 108 : if (str == NULL)
557 0 : return NULL;
558 108 : if (hexstr2bin(value, str, tlen)) {
559 2 : os_free(str);
560 2 : return NULL;
561 : }
562 106 : str[tlen] = '\0';
563 106 : *len = tlen;
564 106 : return (char *) str;
565 : }
566 : }
567 :
568 :
569 14 : int is_hex(const u8 *data, size_t len)
570 : {
571 : size_t i;
572 :
573 59 : for (i = 0; i < len; i++) {
574 50 : if (data[i] < 32 || data[i] >= 127)
575 5 : return 1;
576 : }
577 9 : return 0;
578 : }
579 :
580 :
581 1 : int find_first_bit(u32 value)
582 : {
583 1 : int pos = 0;
584 :
585 2 : while (value) {
586 1 : if (value & 0x1)
587 1 : return pos;
588 0 : value >>= 1;
589 0 : pos++;
590 : }
591 :
592 0 : return -1;
593 : }
594 :
595 :
596 2929 : size_t merge_byte_arrays(u8 *res, size_t res_len,
597 : const u8 *src1, size_t src1_len,
598 : const u8 *src2, size_t src2_len)
599 : {
600 2929 : size_t len = 0;
601 :
602 2929 : os_memset(res, 0, res_len);
603 :
604 2929 : if (src1) {
605 2929 : if (src1_len >= res_len) {
606 0 : os_memcpy(res, src1, res_len);
607 0 : return res_len;
608 : }
609 :
610 2929 : os_memcpy(res, src1, src1_len);
611 2929 : len += src1_len;
612 : }
613 :
614 2929 : if (src2) {
615 2421 : if (len + src2_len >= res_len) {
616 0 : os_memcpy(res + len, src2, res_len - len);
617 0 : return res_len;
618 : }
619 :
620 2421 : os_memcpy(res + len, src2, src2_len);
621 2421 : len += src2_len;
622 : }
623 :
624 2929 : return len;
625 : }
626 :
627 :
628 5810 : char * dup_binstr(const void *src, size_t len)
629 : {
630 : char *res;
631 :
632 5810 : if (src == NULL)
633 0 : return NULL;
634 5810 : res = os_malloc(len + 1);
635 5810 : if (res == NULL)
636 0 : return NULL;
637 5810 : os_memcpy(res, src, len);
638 5810 : res[len] = '\0';
639 :
640 5810 : return res;
641 : }
642 :
643 :
644 2176 : int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
645 : {
646 2176 : struct wpa_freq_range *freq = NULL, *n;
647 2176 : unsigned int count = 0;
648 : const char *pos, *pos2, *pos3;
649 :
650 : /*
651 : * Comma separated list of frequency ranges.
652 : * For example: 2412-2432,2462,5000-6000
653 : */
654 2176 : pos = value;
655 4644 : while (pos && pos[0]) {
656 292 : n = os_realloc_array(freq, count + 1,
657 : sizeof(struct wpa_freq_range));
658 292 : if (n == NULL) {
659 0 : os_free(freq);
660 0 : return -1;
661 : }
662 292 : freq = n;
663 292 : freq[count].min = atoi(pos);
664 292 : pos2 = os_strchr(pos, '-');
665 292 : pos3 = os_strchr(pos, ',');
666 292 : if (pos2 && (!pos3 || pos2 < pos3)) {
667 15 : pos2++;
668 15 : freq[count].max = atoi(pos2);
669 : } else
670 277 : freq[count].max = freq[count].min;
671 292 : pos = pos3;
672 292 : if (pos)
673 17 : pos++;
674 292 : count++;
675 : }
676 :
677 2176 : os_free(res->range);
678 2176 : res->range = freq;
679 2176 : res->num = count;
680 :
681 2176 : return 0;
682 : }
683 :
684 :
685 535743 : int freq_range_list_includes(const struct wpa_freq_range_list *list,
686 : unsigned int freq)
687 : {
688 : unsigned int i;
689 :
690 535743 : if (list == NULL)
691 0 : return 0;
692 :
693 546299 : for (i = 0; i < list->num; i++) {
694 12642 : if (freq >= list->range[i].min && freq <= list->range[i].max)
695 2086 : return 1;
696 : }
697 :
698 533657 : return 0;
699 : }
700 :
701 :
702 2 : char * freq_range_list_str(const struct wpa_freq_range_list *list)
703 : {
704 : char *buf, *pos, *end;
705 : size_t maxlen;
706 : unsigned int i;
707 : int res;
708 :
709 2 : if (list->num == 0)
710 0 : return NULL;
711 :
712 2 : maxlen = list->num * 30;
713 2 : buf = os_malloc(maxlen);
714 2 : if (buf == NULL)
715 0 : return NULL;
716 2 : pos = buf;
717 2 : end = buf + maxlen;
718 :
719 7 : for (i = 0; i < list->num; i++) {
720 5 : struct wpa_freq_range *range = &list->range[i];
721 :
722 5 : if (range->min == range->max)
723 4 : res = os_snprintf(pos, end - pos, "%s%u",
724 : i == 0 ? "" : ",", range->min);
725 : else
726 1 : res = os_snprintf(pos, end - pos, "%s%u-%u",
727 : i == 0 ? "" : ",",
728 : range->min, range->max);
729 5 : if (res < 0 || res > end - pos) {
730 0 : os_free(buf);
731 0 : return NULL;
732 : }
733 5 : pos += res;
734 : }
735 :
736 2 : return buf;
737 : }
738 :
739 :
740 2632 : int int_array_len(const int *a)
741 : {
742 : int i;
743 2632 : for (i = 0; a && a[i]; i++)
744 : ;
745 2632 : return i;
746 : }
747 :
748 :
749 536 : void int_array_concat(int **res, const int *a)
750 : {
751 : int reslen, alen, i;
752 : int *n;
753 :
754 536 : reslen = int_array_len(*res);
755 536 : alen = int_array_len(a);
756 :
757 536 : n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
758 536 : if (n == NULL) {
759 0 : os_free(*res);
760 0 : *res = NULL;
761 536 : return;
762 : }
763 1608 : for (i = 0; i <= alen; i++)
764 1072 : n[reslen + i] = a[i];
765 536 : *res = n;
766 : }
767 :
768 :
769 17 : static int freq_cmp(const void *a, const void *b)
770 : {
771 17 : int _a = *(int *) a;
772 17 : int _b = *(int *) b;
773 :
774 17 : if (_a == 0)
775 0 : return 1;
776 17 : if (_b == 0)
777 0 : return -1;
778 17 : return _a - _b;
779 : }
780 :
781 :
782 1022 : void int_array_sort_unique(int *a)
783 : {
784 : int alen;
785 : int i, j;
786 :
787 1022 : if (a == NULL)
788 1509 : return;
789 :
790 535 : alen = int_array_len(a);
791 535 : qsort(a, alen, sizeof(int), freq_cmp);
792 :
793 535 : i = 0;
794 535 : j = 1;
795 1078 : while (a[i] && a[j]) {
796 8 : if (a[i] == a[j]) {
797 4 : j++;
798 4 : continue;
799 : }
800 4 : a[++i] = a[j++];
801 : }
802 535 : if (a[i])
803 535 : i++;
804 535 : a[i] = 0;
805 : }
806 :
807 :
808 676 : void int_array_add_unique(int **res, int a)
809 : {
810 : int reslen;
811 : int *n;
812 :
813 1700 : for (reslen = 0; *res && (*res)[reslen]; reslen++) {
814 1355 : if ((*res)[reslen] == a)
815 331 : return; /* already in the list */
816 : }
817 :
818 345 : n = os_realloc_array(*res, reslen + 2, sizeof(int));
819 345 : if (n == NULL) {
820 0 : os_free(*res);
821 0 : *res = NULL;
822 0 : return;
823 : }
824 :
825 345 : n[reslen] = a;
826 345 : n[reslen + 1] = 0;
827 :
828 345 : *res = n;
829 : }
|