]> git.ipfire.org Git - people/ms/libloc.git/blob - src/country-list.c
importer: Drop EDROP as it has been merged into DROP
[people/ms/libloc.git] / src / country-list.c
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
20 #include <libloc/compat.h>
21 #include <libloc/country.h>
22 #include <libloc/country-list.h>
23 #include <libloc/private.h>
24
25 struct loc_country_list {
26 struct loc_ctx* ctx;
27 int refcount;
28
29 struct loc_country** elements;
30 size_t elements_size;
31
32 size_t size;
33 };
34
35 static 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
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)
46 return 1;
47
48 list->elements = elements;
49 list->elements_size += size;
50
51 return 0;
52 }
53
54 LOC_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
63 DEBUG(l->ctx, "Country list allocated at %p\n", l);
64 *list = l;
65
66 return 0;
67 }
68
69 LOC_EXPORT struct loc_country_list* loc_country_list_ref(struct loc_country_list* list) {
70 list->refcount++;
71
72 return list;
73 }
74
75 static 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
84 LOC_EXPORT struct loc_country_list* loc_country_list_unref(struct loc_country_list* list) {
85 if (--list->refcount > 0)
86 return list;
87
88 loc_country_list_free(list);
89 return NULL;
90 }
91
92 LOC_EXPORT size_t loc_country_list_size(struct loc_country_list* list) {
93 return list->size;
94 }
95
96 LOC_EXPORT int loc_country_list_empty(struct loc_country_list* list) {
97 return list->size == 0;
98 }
99
100 LOC_EXPORT void loc_country_list_clear(struct loc_country_list* list) {
101 if (!list->elements)
102 return;
103
104 for (unsigned int i = 0; i < list->size; i++)
105 loc_country_unref(list->elements[i]);
106
107 free(list->elements);
108 list->elements = NULL;
109 list->elements_size = 0;
110
111 list->size = 0;
112 }
113
114 LOC_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
119 return loc_country_ref(list->elements[index]);
120 }
121
122 LOC_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
128 if (list->size >= list->elements_size) {
129 int r = loc_country_list_grow(list);
130 if (r)
131 return r;
132 }
133
134 DEBUG(list->ctx, "%p: Appending country %p to list\n", list, country);
135
136 list->elements[list->size++] = loc_country_ref(country);
137
138 return 0;
139 }
140
141 LOC_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++) {
144 if (loc_country_cmp(country, list->elements[i]) == 0)
145 return 1;
146 }
147
148 return 0;
149 }
150
151 LOC_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);
156 if (r) {
157 // Ignore invalid country codes which would never match
158 if (errno == EINVAL)
159 return 0;
160
161 return r;
162 }
163
164 r = loc_country_list_contains(list, country);
165 loc_country_unref(country);
166
167 return r;
168 }
169
170 static 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
174 LOC_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 }