"Fossies" - the Fresh Open Source Software Archive 
Member "tin-2.6.2/src/list.c" (9 Dec 2022, 7314 Bytes) of package /linux/misc/tin-2.6.2.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "list.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.6.1_vs_2.6.2.
1 /*
2 * Project : tin - a Usenet reader
3 * Module : list.c
4 * Author : I. Lea
5 * Created : 1993-12-18
6 * Updated : 2019-01-18
7 * Notes : Low level functions handling the active[] list and its group_hash index
8 *
9 * Copyright (c) 1993-2023 Iain Lea <iain@bricbrac.de>
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 *
23 * 3. Neither the name of the copyright holder nor the names of its
24 * contributors may be used to endorse or promote products derived from
25 * this software without specific prior written permission.
26 *
27 * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40
41 #ifndef TIN_H
42 # include "tin.h"
43 #endif /* !TIN_H */
44 #ifdef DEBUG
45 # ifndef TCURSES_H
46 # include "tcurses.h"
47 # endif /* !TCURSES_H */
48 #endif /* DEBUG */
49
50 static int group_hash[TABLE_SIZE]; /* group name --> active[] */
51
52 /*
53 * local prototypes
54 */
55 static t_bool group_add_to_hash(const char *groupname, int idx);
56 #ifdef DEBUG
57 static void debug_print_active_hash(void);
58 #endif /* DEBUG */
59
60
61 void
62 init_group_hash(
63 void)
64 {
65 int i;
66
67 #if 0
68 if (num_active == -1) {
69 #endif /* 0 */
70 num_active = 0;
71 for (i = 0; i < TABLE_SIZE; i++)
72 group_hash[i] = -1;
73 #if 0
74 }
75 #endif /* 0 */
76 }
77
78
79 /*
80 * hash group name for fast lookup later
81 */
82 unsigned long
83 hash_groupname(
84 const char *group)
85 {
86 unsigned long hash_value = 0L;
87 unsigned int len = 0;
88 const unsigned char *ptr = (const unsigned char *) group;
89
90 while (*ptr) {
91 hash_value = (hash_value << 1) ^ *ptr++;
92 if (++len & 7)
93 continue;
94 hash_value %= TABLE_SIZE;
95 }
96 hash_value %= TABLE_SIZE;
97
98 return hash_value;
99 }
100
101
102 /*
103 * Find group name in active[] array and return index otherwise -1
104 */
105 int
106 find_group_index(
107 const char *group,
108 t_bool ignore_case)
109 {
110 char *group_lcase;
111 int i;
112 unsigned long h;
113
114 group_lcase = my_strdup(group);
115 str_lwr(group_lcase);
116
117 h = hash_groupname(group_lcase);
118 i = group_hash[h];
119
120 free(group_lcase);
121
122 /*
123 * hash linked list chaining
124 * first try to find group in original spelling only
125 */
126 while (i >= 0) {
127 if (STRCMPEQ(group, active[i].name))
128 return i;
129
130 i = active[i].next;
131 }
132
133 /*
134 * group not found in original spelling, try to find not case sensitive
135 * if desired
136 */
137 if (ignore_case) {
138 i = group_hash[h];
139 while (i >= 0) {
140 if (!strcasecmp(group, active[i].name))
141 return i;
142 i = active[i].next;
143 }
144 }
145
146 return -1;
147 }
148
149
150 /*
151 * Find group name in active[] array and return pointer to element
152 */
153 struct t_group *
154 group_find(
155 const char *group_name,
156 t_bool ignore_case)
157 {
158 int i;
159
160 if ((i = find_group_index(group_name, ignore_case)) != -1)
161 return &active[i];
162
163 return (struct t_group *) 0;
164 }
165
166
167 /*
168 * Hash the groupname into group_hash[]
169 * Return FALSE if the group is already present
170 */
171 static t_bool
172 group_add_to_hash(
173 const char *groupname,
174 int idx)
175 {
176 char *groupname_lcase;
177 unsigned long h;
178
179 groupname_lcase = my_strdup(groupname);
180 str_lwr(groupname_lcase);
181 h = hash_groupname(groupname_lcase);
182 free(groupname_lcase);
183
184 if (group_hash[h] == -1)
185 group_hash[h] = idx;
186 else {
187 int i;
188
189 /*
190 * hash linked list chaining
191 */
192 for (i = group_hash[h]; active[i].next >= 0; i = active[i].next) {
193 if (STRCMPEQ(active[i].name, groupname))
194 return FALSE; /* Already in chain */
195 }
196
197 if (STRCMPEQ(active[i].name, groupname))
198 return FALSE; /* Already on end of chain */
199
200 active[i].next = idx; /* Append to chain */
201 }
202
203 return TRUE;
204 }
205
206
207 /*
208 * Make sure memory available for next active slot
209 * Adds group to the group_hash of active groups and name it
210 * Return pointer to next free active slot or NULL if duplicate
211 */
212 struct t_group *
213 group_add(
214 const char *group)
215 {
216 if (num_active >= max_active) /* Grow memory area if needed */
217 expand_active();
218
219 if (!(group_add_to_hash(group, num_active)))
220 return NULL;
221
222 active[num_active].name = my_strdup(group);
223
224 return &active[num_active++]; /* NB num_active incremented here */
225 }
226
227
228 /*
229 * Reinitialise group_hash[] after change to ordering of active[]
230 */
231 void
232 group_rehash(
233 t_bool yanked_out)
234 {
235 int i;
236 int save_num_active = num_active;
237
238 init_group_hash(); /* Clear the existing hash */
239 num_active = save_num_active; /* init_group_hash() resets this */
240
241 for_each_group(i)
242 active[i].next = -1;
243
244 /*
245 * Now rehash each group and rebuild my_group[]
246 */
247 selmenu.max = 0;
248
249 for_each_group(i) {
250 group_add_to_hash(active[i].name, i);
251
252 /*
253 * cf: similar code to toggle_my_groups()
254 * Add a group if all groups are yanked in
255 * If we are yanked out, only consider subscribed groups
256 * Then also honour show_only_unread and BOGUS_SHOW
257 */
258 if (!yanked_out) {
259 my_group[selmenu.max++] = i;
260 continue;
261 }
262
263 if (active[i].subscribed) {
264 if (tinrc.show_only_unread_groups) {
265 if (active[i].newsrc.num_unread > 0 || (active[i].bogus && tinrc.strip_bogus == BOGUS_SHOW))
266 my_group[selmenu.max++] = i;
267 } else
268 my_group[selmenu.max++] = i;
269 }
270 }
271
272 #ifdef DEBUG
273 if (debug & DEBUG_MISC)
274 debug_print_active_hash();
275 #endif /* DEBUG */
276 }
277
278
279 #ifdef DEBUG
280 /*
281 * Prints out hash distribution of active[]
282 */
283 static void
284 debug_print_active_hash(
285 void)
286 {
287 int empty = 0;
288 int collisions[32];
289 int i;
290
291 for (i = 0; i < 32; i++)
292 collisions[i] = 0;
293
294 for (i = 0; i < TABLE_SIZE; i++) {
295 /* my_printf("HASH[%4d] ", i); */
296
297 if (group_hash[i] == -1) {
298 /* my_printf("EMPTY\n"); */
299 empty++;
300 } else {
301 int j;
302 int number = 0;
303
304 for (j = group_hash[i]; active[j].next >= 0; j = active[j].next)
305 number++;
306
307 if (number > 31)
308 fprintf(stderr, "MEGA HASH COLLISION > 31 HASH[%d]=[%d]!!!\n", i, number);
309 else
310 collisions[number]++;
311 }
312 }
313
314 fprintf(stderr, "HashTable Active=[%d] Size=[%d] Filled=[%d] Empty=[%d]\n",
315 num_active, TABLE_SIZE, TABLE_SIZE - empty, empty);
316 fprintf(stderr, "00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32\n");
317 fprintf(stderr, "--------------------------------------------------------------------------------------------------\n");
318 for (i = 0; i < 32; i++)
319 fprintf(stderr, "%2d ", collisions[i]);
320 fprintf(stderr, "\n");
321 sleep(4);
322 }
323 #endif /* DEBUG */