]> git.ipfire.org Git - location/libloc.git/blame - src/country-list.c
importer: Drop EDROP as it has been merged into DROP
[location/libloc.git] / src / country-list.c
CommitLineData
e646a8f3
MT
1/*
2 libloc - A library to determine the location of someone on the Internet
3
4 Copyright (C) 2020 IPFire Development Team <info@ipfire.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15*/
16
17#include <errno.h>
18#include <stdlib.h>
19
25f300f7 20#include <libloc/compat.h>
c12a1385
MT
21#include <libloc/country.h>
22#include <libloc/country-list.h>
23#include <libloc/private.h>
e646a8f3
MT
24
25struct loc_country_list {
26 struct loc_ctx* ctx;
27 int refcount;
28
d5205091
MT
29 struct loc_country** elements;
30 size_t elements_size;
31
e646a8f3 32 size_t size;
e646a8f3
MT
33};
34
7db88f1b
MT
35static int loc_country_list_grow(struct loc_country_list* list) {
36 size_t size = list->elements_size * 2;
37 if (size < 1024)
38 size = 1024;
39
d5205091
MT
40 DEBUG(list->ctx, "Growing country list %p by %zu to %zu\n",
41 list, size, list->elements_size + size);
42
43 struct loc_country** elements = reallocarray(list->elements,
44 list->elements_size + size, sizeof(*list->elements));
45 if (!elements)
198e382c 46 return 1;
d5205091
MT
47
48 list->elements = elements;
49 list->elements_size += size;
50
51 return 0;
52}
53
e646a8f3
MT
54LOC_EXPORT int loc_country_list_new(struct loc_ctx* ctx,
55 struct loc_country_list** list) {
56 struct loc_country_list* l = calloc(1, sizeof(*l));
57 if (!l)
58 return -ENOMEM;
59
60 l->ctx = loc_ref(ctx);
61 l->refcount = 1;
62
e646a8f3
MT
63 DEBUG(l->ctx, "Country list allocated at %p\n", l);
64 *list = l;
65
66 return 0;
67}
68
69LOC_EXPORT struct loc_country_list* loc_country_list_ref(struct loc_country_list* list) {
70 list->refcount++;
71
72 return list;
73}
74
75static void loc_country_list_free(struct loc_country_list* list) {
76 DEBUG(list->ctx, "Releasing country list at %p\n", list);
77
78 loc_country_list_clear(list);
79
80 loc_unref(list->ctx);
81 free(list);
82}
83
84LOC_EXPORT struct loc_country_list* loc_country_list_unref(struct loc_country_list* list) {
e646a8f3
MT
85 if (--list->refcount > 0)
86 return list;
87
88 loc_country_list_free(list);
89 return NULL;
90}
91
92LOC_EXPORT size_t loc_country_list_size(struct loc_country_list* list) {
93 return list->size;
94}
95
96LOC_EXPORT int loc_country_list_empty(struct loc_country_list* list) {
97 return list->size == 0;
98}
99
100LOC_EXPORT void loc_country_list_clear(struct loc_country_list* list) {
248f5e04
MT
101 if (!list->elements)
102 return;
103
e646a8f3 104 for (unsigned int i = 0; i < list->size; i++)
d5205091 105 loc_country_unref(list->elements[i]);
248f5e04
MT
106
107 free(list->elements);
a6dc9324 108 list->elements = NULL;
248f5e04
MT
109 list->elements_size = 0;
110
111 list->size = 0;
e646a8f3
MT
112}
113
114LOC_EXPORT struct loc_country* loc_country_list_get(struct loc_country_list* list, size_t index) {
115 // Check index
116 if (index >= list->size)
117 return NULL;
118
d5205091 119 return loc_country_ref(list->elements[index]);
e646a8f3
MT
120}
121
122LOC_EXPORT int loc_country_list_append(
123 struct loc_country_list* list, struct loc_country* country) {
124 if (loc_country_list_contains(list, country))
125 return 0;
126
127 // Check if we have space left
d5205091 128 if (list->size >= list->elements_size) {
7db88f1b 129 int r = loc_country_list_grow(list);
d5205091
MT
130 if (r)
131 return r;
e646a8f3
MT
132 }
133
134 DEBUG(list->ctx, "%p: Appending country %p to list\n", list, country);
135
d5205091 136 list->elements[list->size++] = loc_country_ref(country);
e646a8f3
MT
137
138 return 0;
139}
140
141LOC_EXPORT int loc_country_list_contains(
142 struct loc_country_list* list, struct loc_country* country) {
143 for (unsigned int i = 0; i < list->size; i++) {
d5205091 144 if (loc_country_cmp(country, list->elements[i]) == 0)
e646a8f3
MT
145 return 1;
146 }
147
148 return 0;
149}
150
151LOC_EXPORT int loc_country_list_contains_code(
152 struct loc_country_list* list, const char* code) {
153 struct loc_country* country;
154
155 int r = loc_country_new(list->ctx, &country, code);
e73b7709
MT
156 if (r) {
157 // Ignore invalid country codes which would never match
158 if (errno == EINVAL)
159 return 0;
198e382c
MT
160
161 return r;
e73b7709 162 }
e646a8f3
MT
163
164 r = loc_country_list_contains(list, country);
165 loc_country_unref(country);
166
167 return r;
168}
3df5f70a
MT
169
170static int __loc_country_cmp(const void* country1, const void* country2) {
171 return loc_country_cmp(*(struct loc_country**)country1, *(struct loc_country**)country2);
172}
173
174LOC_EXPORT void loc_country_list_sort(struct loc_country_list* list) {
175 // Sort everything
176 qsort(list->elements, list->size, sizeof(*list->elements), __loc_country_cmp);
177}