summaryrefslogtreecommitdiff
path: root/vchat-user.c
diff options
context:
space:
mode:
Diffstat (limited to 'vchat-user.c')
-rwxr-xr-xvchat-user.c399
1 files changed, 223 insertions, 176 deletions
diff --git a/vchat-user.c b/vchat-user.c
index 881a3cf..1ab2048 100755
--- a/vchat-user.c
+++ b/vchat-user.c
@@ -3,42 +3,48 @@
3 3
4*/ 4*/
5 5
6#include <regex.h>
6#include <stdint.h> 7#include <stdint.h>
8#include <stdio.h>
7#include <stdlib.h> 9#include <stdlib.h>
8#include <strings.h> 10#include <strings.h>
9#include <stdio.h>
10#include <sys/time.h> 11#include <sys/time.h>
11#include <regex.h> 12
12#include <readline/readline.h> 13#include <readline/readline.h>
13 14
14#include "vchat.h"
15#include "vchat-user.h" 15#include "vchat-user.h"
16#include "vchat.h"
16 17
17/* version of this module */ 18/* version of this module */
18char *vchat_us_version = "vchat-user.c $Id$"; 19char *vchat_us_version =
19 20 "vchat-user.c $Id$";
20typedef struct 21
21{ 22typedef struct {
22 char *nick; 23 char *nick;
23 enum { UL_NONE = 0x00, UL_ME = 0x01, UL_IN_MY_CHAN = 0x02, UL_NOT_IN_LIST = 0x04 } flags; 24 enum {
25 UL_NONE = 0x00,
26 UL_ME = 0x01,
27 UL_IN_MY_CHAN = 0x02,
28 UL_NOT_IN_LIST = 0x04
29 } flags;
24 uint64_t last_public; 30 uint64_t last_public;
25 uint64_t last_private; 31 uint64_t last_private;
26} user; 32} user;
27static user *g_users; //< all users, incl self 33static user *g_users; //< all users, incl self
28static size_t g_users_count; //< number of users in list 34static size_t g_users_count; //< number of users in list
29static char *g_nick; //< own nick 35static char *g_nick; //< own nick
30static int g_channel; //< own channel 36static int g_channel; //< own channel
31unsigned int ul_case_first = 0; 37unsigned int ul_case_first = 0;
32 38
33static char **g_dict; 39static char **g_dict;
34static size_t g_dict_len; 40static size_t g_dict_len;
35 41
36static int ul_nick_lookup( const char *nick, int *exact_match ) { 42static int ul_nick_lookup(const char *nick, int *exact_match) {
37 int i; 43 int i;
38 44
39 *exact_match = 1; 45 *exact_match = 1;
40 for( i=0; i<g_users_count; ++i ) 46 for (i = 0; i < g_users_count; ++i)
41 if( !strcasecmp( g_users[i].nick, nick ) ) 47 if (!strcasecmp(g_users[i].nick, nick))
42 return i; 48 return i;
43 *exact_match = 0; 49 *exact_match = 0;
44 return i; 50 return i;
@@ -46,78 +52,83 @@ static int ul_nick_lookup( const char *nick, int *exact_match ) {
46 52
47static int64_t ul_now() { 53static int64_t ul_now() {
48 struct timeval now; 54 struct timeval now;
49 gettimeofday(&now,(struct timezone*) 0); 55 gettimeofday(&now, (struct timezone *)0);
50 return ((uint64_t)now.tv_sec * 1000) + ((uint64_t)now.tv_usec / 1000 ); 56 return ((uint64_t)now.tv_sec * 1000) + ((uint64_t)now.tv_usec / 1000);
51} 57}
52 58
53/* own nick and channel setters/getters */ 59/* own nick and channel setters/getters */
54void own_nick_set( char *nick ) { 60void own_nick_set(char *nick) {
55 if( nick ) { 61 if (nick) {
56 int base; 62 int base;
57 if( g_nick ) 63 if (g_nick)
58 base = ul_rename( g_nick, nick ); 64 base = ul_rename(g_nick, nick);
59 else 65 else
60 base = ul_add( nick, 0 ); 66 base = ul_add(nick, 0);
61 if( base >= 0 ) { 67 if (base >= 0) {
62 g_users[base].flags |= UL_ME; 68 g_users[base].flags |= UL_ME;
63 g_nick = g_users[base].nick; 69 g_nick = g_users[base].nick;
64 } 70 }
65 } else 71 } else
66 ul_del( g_nick ); 72 ul_del(g_nick);
67 73
68 setstroption(CF_NICK, nick); 74 setstroption(CF_NICK, nick);
69} 75}
70 76
71void own_channel_set( int channel ) { 77void own_channel_set(int channel) {
72 if( channel != g_channel ) { 78 if (channel != g_channel) {
73 /* Remove all users from my chan, will be re-set on join message */ 79 /* Remove all users from my chan, will be re-set on join message */
74 int i; 80 int i;
75 for( i=0; i<g_users_count; ++i ) 81 for (i = 0; i < g_users_count; ++i)
76 g_users[i].flags &= ~UL_IN_MY_CHAN; 82 g_users[i].flags &= ~UL_IN_MY_CHAN;
77 } 83 }
78 84
79 g_channel = channel; 85 g_channel = channel;
80} 86}
81 87
82char const *own_nick_get( ) { 88char const *own_nick_get() { return g_nick; }
83 return g_nick;
84}
85 89
86int own_nick_check( char *nick ) { 90int own_nick_check(char *nick) {
87 if( !g_nick ) return -1; 91 if (!g_nick)
88 return !strcasecmp(g_nick,nick); 92 return -1;
93 return !strcasecmp(g_nick, nick);
89} 94}
90 95
91int own_channel_get( ) { 96int own_channel_get() { return g_channel; }
92 return g_channel;
93}
94 97
95/* Add/remove/rename */ 98/* Add/remove/rename */
96int ul_add(char *name, int in_my_chan_flag ) { 99int ul_add(char *name, int in_my_chan_flag) {
97 100
98 /* Test if user is already known */ 101 /* Test if user is already known */
99 int exact_match, base = ul_nick_lookup( name, &exact_match ); 102 int exact_match, base = ul_nick_lookup(name, &exact_match);
100 if( !exact_match ) { 103 if (!exact_match) {
101 /* Make space for new user */ 104 /* Make space for new user */
102 user * new_users = realloc( g_users, sizeof( user ) * ( 1 + g_users_count ) ); 105 user *new_users = realloc(g_users, sizeof(user) * (1 + g_users_count));
103 if( !new_users ) return -1; 106 if (!new_users)
107 return -1;
104 108
105 /* Copy the tail */ 109 /* Copy the tail */
106 g_users = new_users; 110 g_users = new_users;
107 memmove( g_users + base + 1, g_users + base, ( g_users_count - base ) * sizeof( user ) ); 111 memmove(g_users + base + 1, g_users + base,
108 g_users[base].nick = strdup( name ); 112 (g_users_count - base) * sizeof(user));
109 g_users[base].flags = UL_NONE; 113 g_users[base].nick = strdup(name);
110 g_users[base].last_public = 0; 114 g_users[base].flags = UL_NONE;
115 g_users[base].last_public = 0;
111 g_users[base].last_private = 0; 116 g_users[base].last_private = 0;
112 117
113 g_users_count++; 118 g_users_count++;
114 } 119 }
115 120
116 g_users[base].flags &= ~UL_NOT_IN_LIST; 121 g_users[base].flags &= ~UL_NOT_IN_LIST;
117 switch( in_my_chan_flag ) { 122 switch (in_my_chan_flag) {
118 case 1: g_users[base].flags |= UL_IN_MY_CHAN; break; 123 case 1:
119 case 0: g_users[base].flags &= ~UL_IN_MY_CHAN; break; 124 g_users[base].flags |= UL_IN_MY_CHAN;
120 case -1: default: break; 125 break;
126 case 0:
127 g_users[base].flags &= ~UL_IN_MY_CHAN;
128 break;
129 case -1:
130 default:
131 break;
121 } 132 }
122 133
123 return base; 134 return base;
@@ -125,30 +136,33 @@ int ul_add(char *name, int in_my_chan_flag ) {
125 136
126int ul_del(char *name) { 137int ul_del(char *name) {
127 /* Test if user is already known */ 138 /* Test if user is already known */
128 int exact_match, base = ul_nick_lookup( name, &exact_match ); 139 int exact_match, base = ul_nick_lookup(name, &exact_match);
129 if( !exact_match ) return -1; 140 if (!exact_match)
141 return -1;
130 142
131 /* Release the name buffer */ 143 /* Release the name buffer */
132 free( g_users[base].nick ); 144 free(g_users[base].nick);
133 if( g_users[base].flags & UL_ME ) g_nick = 0; 145 if (g_users[base].flags & UL_ME)
146 g_nick = 0;
134 147
135 /* Copy the tail */ 148 /* Copy the tail */
136 memmove( g_users + base, g_users + base + 1, ( g_users_count - base - 1 ) * sizeof( user ) ); 149 memmove(g_users + base, g_users + base + 1,
150 (g_users_count - base - 1) * sizeof(user));
137 151
138 /* Shrink user list, realloc to a smaller size never fails */ 152 /* Shrink user list, realloc to a smaller size never fails */
139 g_users = realloc( g_users, sizeof( user ) * --g_users_count ); 153 g_users = realloc(g_users, sizeof(user) * --g_users_count);
140 return 0; 154 return 0;
141} 155}
142 156
143int ul_rename(char *oldname, char *newname) { 157int ul_rename(char *oldname, char *newname) {
144 /* Ensure user */ 158 /* Ensure user */
145 int base = ul_add( oldname, -1 ); 159 int base = ul_add(oldname, -1);
146 if( base >= 0 ) { 160 if (base >= 0) {
147 free( g_users[base].nick ); 161 free(g_users[base].nick);
148 g_users[base].nick = strdup( newname ); 162 g_users[base].nick = strdup(newname);
149 if( g_users[base].flags & UL_ME ) 163 if (g_users[base].flags & UL_ME)
150 g_nick = g_users[base].nick; 164 g_nick = g_users[base].nick;
151 if( g_users[base].flags & UL_IN_MY_CHAN ) 165 if (g_users[base].flags & UL_IN_MY_CHAN)
152 ul_public_action(newname); 166 ul_public_action(newname);
153 } 167 }
154 return base; 168 return base;
@@ -156,23 +170,23 @@ int ul_rename(char *oldname, char *newname) {
156 170
157void ul_clear() { 171void ul_clear() {
158 int i; 172 int i;
159 for( i=0; i<g_users_count; ++i ) 173 for (i = 0; i < g_users_count; ++i)
160 free( g_users[i].nick ); 174 free(g_users[i].nick);
161 free( g_users ); 175 free(g_users);
162 g_nick = 0; 176 g_nick = 0;
163} 177}
164 178
165void ul_rebuild_list( ) { 179void ul_rebuild_list() {
166 int i; 180 int i;
167 for( i=0; i<g_users_count; ++i ) 181 for (i = 0; i < g_users_count; ++i)
168 g_users[i].flags |= UL_NOT_IN_LIST; 182 g_users[i].flags |= UL_NOT_IN_LIST;
169} 183}
170 184
171void ul_clean() { 185void ul_clean() {
172 int i; 186 int i;
173 for( i=0; i<g_users_count; ++i ) { 187 for (i = 0; i < g_users_count; ++i) {
174 if( g_users[i].flags & UL_NOT_IN_LIST ) { 188 if (g_users[i].flags & UL_NOT_IN_LIST) {
175 ul_del( g_users[i].nick ); 189 ul_del(g_users[i].nick);
176 --i; 190 --i;
177 } 191 }
178 } 192 }
@@ -187,237 +201,270 @@ void ul_leave_chan(char *name) {
187void ul_enter_chan(char *name) { 201void ul_enter_chan(char *name) {
188 /* Ensure user and put him on the channel */ 202 /* Ensure user and put him on the channel */
189 int base = ul_add(name, 1); 203 int base = ul_add(name, 1);
190 if( base >= 0 ) 204 if (base >= 0)
191 ul_public_action(name); 205 ul_public_action(name);
192 206
193 /* Reflect in UI */ 207 /* Reflect in UI */
194 if( own_nick_check( name ) ) 208 if (own_nick_check(name))
195 ownjoin( g_channel ); 209 ownjoin(g_channel);
196} 210}
197 211
198void ul_private_action(char *name) { 212void ul_private_action(char *name) {
199 /* Ensure user and keep channel state */ 213 /* Ensure user and keep channel state */
200 int base = ul_add(name, -1); 214 int base = ul_add(name, -1);
201 if( base >= 0 ) 215 if (base >= 0)
202 g_users[base].last_private = ul_now(); 216 g_users[base].last_private = ul_now();
203} 217}
204 218
205void ul_public_action(char *name) { 219void ul_public_action(char *name) {
206 /* Ensure user and put him on the channel */ 220 /* Ensure user and put him on the channel */
207 int base = ul_add(name, 1); 221 int base = ul_add(name, 1);
208 if( base >= 0 ) 222 if (base >= 0)
209 g_users[base].last_public = ul_now(); 223 g_users[base].last_public = ul_now();
210} 224}
211 225
212void ul_add_to_dict(char *dict_items) { 226void ul_add_to_dict(char *dict_items) {
213 char *i; 227 char *i;
214 for(i=strtok(dict_items," ");i;i=strtok(0," ")) { 228 for (i = strtok(dict_items, " "); i; i = strtok(0, " ")) {
215 g_dict = realloc( g_dict, sizeof(char*) * ( 1 + g_dict_len ) ); 229 g_dict = realloc(g_dict, sizeof(char *) * (1 + g_dict_len));
216 if( !g_dict ) exit(1); 230 if (!g_dict)
231 exit(1);
217 g_dict[g_dict_len++] = strdup(i); 232 g_dict[g_dict_len++] = strdup(i);
218 } 233 }
219} 234}
220 235
221/* Finding users ul_finduser? */ 236/* Finding users ul_finduser? */
222char * ul_match_user(char *regex) { 237char *ul_match_user(char *regex) {
223 char *dest = tmpstr; 238 char *dest = tmpstr;
224 int i; 239 int i;
225 regex_t preg; 240 regex_t preg;
226 241
227 *dest = 0; 242 *dest = 0;
228 if( !regcomp( &preg, regex, REG_ICASE | REG_EXTENDED | REG_NEWLINE)) { 243 if (!regcomp(&preg, regex, REG_ICASE | REG_EXTENDED | REG_NEWLINE)) {
229 244
230 /* does the username match? */ 245 /* does the username match? */
231 /* XXX overflow for too many matches */ 246 /* XXX overflow for too many matches */
232 for( i=0; i<g_users_count; ++i ) 247 for (i = 0; i < g_users_count; ++i)
233 if( !regexec( &preg, g_users[i].nick, 0, NULL, 0)) /* append username to list */ 248 if (!regexec(&preg, g_users[i].nick, 0, NULL,
234 dest += snprintf ( dest, 256, " %s", g_users[i].nick); 249 0)) /* append username to list */
235 250 dest += snprintf(dest, 256, " %s", g_users[i].nick);
236 } 251 }
237 regfree( &preg ); 252 regfree(&preg);
238 return tmpstr; 253 return tmpstr;
239} 254}
240 255
241static int ul_compare_private( const void *a, const void *b ) { 256static int ul_compare_private(const void *a, const void *b) {
242 const user *_a = (const user *)a, *_b = (const user *)b; 257 const user *_a = (const user *)a, *_b = (const user *)b;
243 if( _a->last_private > _b->last_private ) return -1; 258 if (_a->last_private > _b->last_private)
259 return -1;
244 return 1; 260 return 1;
245} 261}
246 262
247static int ul_compare_begin_of_line_ncase( const void *a, const void *b ) { 263static int ul_compare_begin_of_line_ncase(const void *a, const void *b) {
248 const user *_a = (const user *)a, *_b = (const user *)b; 264 const user *_a = (const user *)a, *_b = (const user *)b;
249 size_t tmpstr_len; 265 size_t tmpstr_len;
250 int a_i, b_i; 266 int a_i, b_i;
251 267
252 /* First ensure that users in current channel win */ 268 /* First ensure that users in current channel win */
253 if( !(_a->flags & UL_IN_MY_CHAN ) ) return 1; 269 if (!(_a->flags & UL_IN_MY_CHAN))
254 if( !(_b->flags & UL_IN_MY_CHAN ) ) return -1; 270 return 1;
255 271 if (!(_b->flags & UL_IN_MY_CHAN))
256 tmpstr_len = strlen( tmpstr ); 272 return -1;
257 a_i = strncasecmp( _a->nick, tmpstr, tmpstr_len ); 273
258 b_i = strncasecmp( _b->nick, tmpstr, tmpstr_len ); 274 tmpstr_len = strlen(tmpstr);
259 275 a_i = strncasecmp(_a->nick, tmpstr, tmpstr_len);
260 if( a_i && b_i ) return 0; // Both nicks dont match 276 b_i = strncasecmp(_b->nick, tmpstr, tmpstr_len);
261 if( !a_i && b_i ) return -1; // a matches insensitive, b doesnt 277
262 if( a_i && !b_i ) return 1; // b matches insensitive, a doesnt 278 if (a_i && b_i)
279 return 0; // Both nicks dont match
280 if (!a_i && b_i)
281 return -1; // a matches insensitive, b doesnt
282 if (a_i && !b_i)
283 return 1; // b matches insensitive, a doesnt
263 284
264 /* From here both nicks match the prefix, ensure that own_nick 285 /* From here both nicks match the prefix, ensure that own_nick
265 always appears last */ 286 always appears last */
266 if( _a->flags & UL_ME ) return 1; 287 if (_a->flags & UL_ME)
267 if( _b->flags & UL_ME ) return -1; 288 return 1;
289 if (_b->flags & UL_ME)
290 return -1;
268 291
269 /* Now the user with the most recent public activity wins */ 292 /* Now the user with the most recent public activity wins */
270 if( _a->last_public > _b->last_public ) return -1; 293 if (_a->last_public > _b->last_public)
294 return -1;
271 295
272 return 1; 296 return 1;
273} 297}
274 298
275static int ul_compare_begin_of_line_case( const void *a, const void *b ) { 299static int ul_compare_begin_of_line_case(const void *a, const void *b) {
276 const user *_a = (const user *)a, *_b = (const user *)b; 300 const user *_a = (const user *)a, *_b = (const user *)b;
277 size_t tmpstr_len; 301 size_t tmpstr_len;
278 int a_i, b_i, a_s, b_s; 302 int a_i, b_i, a_s, b_s;
279 303
280 /* First ensure that users in current channel win */ 304 /* First ensure that users in current channel win */
281 if( !(_a->flags & UL_IN_MY_CHAN ) ) return 1; 305 if (!(_a->flags & UL_IN_MY_CHAN))
282 if( !(_b->flags & UL_IN_MY_CHAN ) ) return -1; 306 return 1;
283 307 if (!(_b->flags & UL_IN_MY_CHAN))
284 tmpstr_len = strlen( tmpstr ); 308 return -1;
285 a_i = strncasecmp( _a->nick, tmpstr, tmpstr_len ); 309
286 a_s = strncmp ( _a->nick, tmpstr, tmpstr_len ); 310 tmpstr_len = strlen(tmpstr);
287 b_i = strncasecmp( _b->nick, tmpstr, tmpstr_len ); 311 a_i = strncasecmp(_a->nick, tmpstr, tmpstr_len);
288 b_s = strncmp ( _b->nick, tmpstr, tmpstr_len ); 312 a_s = strncmp(_a->nick, tmpstr, tmpstr_len);
289 313 b_i = strncasecmp(_b->nick, tmpstr, tmpstr_len);
290 if( a_i && b_i ) return 0; // Both nicks dont match at all 314 b_s = strncmp(_b->nick, tmpstr, tmpstr_len);
291 if( !a_i && b_i ) return -1; // a matches insensitive, b doesnt 315
292 if( a_i && !b_i ) return 1; // b matches insensitive, a doesnt 316 if (a_i && b_i)
293 317 return 0; // Both nicks dont match at all
294 if( !a_s && b_s ) return -1; // a matches sensitive, b doesnt 318 if (!a_i && b_i)
295 if( a_s && !b_s ) return 1; // b matches sensitive, a doesnt 319 return -1; // a matches insensitive, b doesnt
320 if (a_i && !b_i)
321 return 1; // b matches insensitive, a doesnt
322
323 if (!a_s && b_s)
324 return -1; // a matches sensitive, b doesnt
325 if (a_s && !b_s)
326 return 1; // b matches sensitive, a doesnt
296 327
297 /* From now we know that both match with same quality, ensure 328 /* From now we know that both match with same quality, ensure
298 that own nick always appears last */ 329 that own nick always appears last */
299 if( _a->flags & UL_ME ) return 1; 330 if (_a->flags & UL_ME)
300 if( _b->flags & UL_ME ) return -1; 331 return 1;
332 if (_b->flags & UL_ME)
333 return -1;
301 334
302 /* Now the user with the most recent public activity wins */ 335 /* Now the user with the most recent public activity wins */
303 if( _a->last_public > _b->last_public ) return -1; 336 if (_a->last_public > _b->last_public)
337 return -1;
304 338
305 return 1; 339 return 1;
306} 340}
307 341
308static int ul_compare_middle_ncase( const void *a, const void *b ) { 342static int ul_compare_middle_ncase(const void *a, const void *b) {
309 const user *_a = (const user *)a, *_b = (const user *)b; 343 const user *_a = (const user *)a, *_b = (const user *)b;
310 344
311 /* Ensure that own nick appears last in list */ 345 /* Ensure that own nick appears last in list */
312 if( _a->flags & UL_ME ) return 1; 346 if (_a->flags & UL_ME)
313 if( _b->flags & UL_ME ) return -1; 347 return 1;
348 if (_b->flags & UL_ME)
349 return -1;
314 350
315 return strcasecmp( _a->nick, _b->nick ); 351 return strcasecmp(_a->nick, _b->nick);
316} 352}
317 353
318static int ul_compare_middle_case( const void *a, const void *b ) { 354static int ul_compare_middle_case(const void *a, const void *b) {
319 const user *_a = (const user *)a, *_b = (const user *)b; 355 const user *_a = (const user *)a, *_b = (const user *)b;
320 size_t tmpstr_len; 356 size_t tmpstr_len;
321 int a_s, b_s; 357 int a_s, b_s;
322 358
323 /* Ensure that own nick appears last in list */ 359 /* Ensure that own nick appears last in list */
324 if( _a->flags & UL_ME ) return 1; 360 if (_a->flags & UL_ME)
325 if( _b->flags & UL_ME ) return -1; 361 return 1;
362 if (_b->flags & UL_ME)
363 return -1;
326 364
327 tmpstr_len = strlen( tmpstr ); 365 tmpstr_len = strlen(tmpstr);
328 a_s = strncmp( _a->nick, tmpstr, tmpstr_len ); 366 a_s = strncmp(_a->nick, tmpstr, tmpstr_len);
329 b_s = strncmp( _b->nick, tmpstr, tmpstr_len ); 367 b_s = strncmp(_b->nick, tmpstr, tmpstr_len);
330 368
331 if( !a_s && b_s ) return -1; // a matches sensitive, b doesnt 369 if (!a_s && b_s)
332 if( a_s && !b_s ) return 1; // b matches sensitive, a doesnt 370 return -1; // a matches sensitive, b doesnt
371 if (a_s && !b_s)
372 return 1; // b matches sensitive, a doesnt
333 373
334 /* From now both strings either both or both dont match 374 /* From now both strings either both or both dont match
335 decide their position by case insensitive match */ 375 decide their position by case insensitive match */
336 return strcasecmp( _a->nick, _b->nick ); 376 return strcasecmp(_a->nick, _b->nick);
337} 377}
338 378
339/* Nick completion function for readline */ 379/* Nick completion function for readline */
340char **ul_complete_user(char *text, int start, int end ) { 380char **ul_complete_user(char *text, int start, int end) {
341 char **result = 0; 381 char **result = 0;
342 int i, result_count = 0, dict_result_count = 0; 382 int i, result_count = 0, dict_result_count = 0;
343 383
344 /* Never want readline to complete filenames */ 384 /* Never want readline to complete filenames */
345 rl_attempted_completion_over = 1; 385 rl_attempted_completion_over = 1;
346 386
347 /* Check for amount of custom dict matches */ 387 /* Check for amount of custom dict matches */
348 if( end && ( start != end ) ) 388 if (end && (start != end))
349 for( i=0; i<g_dict_len; ++i ) 389 for (i = 0; i < g_dict_len; ++i)
350 if( !strncasecmp( g_dict[i], text+start, end-start ) ) 390 if (!strncasecmp(g_dict[i], text + start, end - start))
351 ++dict_result_count; 391 ++dict_result_count;
352 392
353 /* Prepare return array ... of max g_users_count (char*) 393 /* Prepare return array ... of max g_users_count (char*)
354 Plus least common prefix in [0] and null terminator 394 Plus least common prefix in [0] and null terminator
355 */ 395 */
356 result = malloc( sizeof(char*) * ( 2 + g_users_count + dict_result_count ) ); 396 result = malloc(sizeof(char *) * (2 + g_users_count + dict_result_count));
357 if( !result ) return 0; 397 if (!result)
398 return 0;
358 399
359 if( start == 0 && end == 0 ) { 400 if (start == 0 && end == 0) {
360 /* Completion on begin of line yields list of everyone we 401 /* Completion on begin of line yields list of everyone we
361 were in private conversation, sorted by time of last .m */ 402 were in private conversation, sorted by time of last .m */
362 qsort( g_users, g_users_count, sizeof(user), ul_compare_private ); 403 qsort(g_users, g_users_count, sizeof(user), ul_compare_private);
363 for( i=0; i<g_users_count; ++i ) 404 for (i = 0; i < g_users_count; ++i)
364 if( g_users[i].last_private ) { 405 if (g_users[i].last_private) {
365 snprintf( tmpstr, TMPSTRSIZE, ".m %s", g_users[i].nick ); 406 snprintf(tmpstr, TMPSTRSIZE, ".m %s", g_users[i].nick);
366 result[++result_count] = strdup(tmpstr); 407 result[++result_count] = strdup(tmpstr);
367 } 408 }
368 /* No common prefix */ 409 /* No common prefix */
369 if( result_count ) result[0] = strdup(""); 410 if (result_count)
411 result[0] = strdup("");
370 412
371 } else if( start == 0 && end > 0 ) { 413 } else if (start == 0 && end > 0) {
372 /* Completion on begin of line with some chars already typed yields 414 /* Completion on begin of line with some chars already typed yields
373 a list of everyone in channel, matching prefix, sorted by last 415 a list of everyone in channel, matching prefix, sorted by last
374 public activity */ 416 public activity */
375 snprintf( tmpstr, end + 1, "%s", text ); 417 snprintf(tmpstr, end + 1, "%s", text);
376 if( ul_case_first ) 418 if (ul_case_first)
377 qsort( g_users, g_users_count, sizeof(user), ul_compare_begin_of_line_case ); 419 qsort(g_users, g_users_count, sizeof(user),
420 ul_compare_begin_of_line_case);
378 else 421 else
379 qsort( g_users, g_users_count, sizeof(user), ul_compare_begin_of_line_ncase ); 422 qsort(g_users, g_users_count, sizeof(user),
423 ul_compare_begin_of_line_ncase);
380 424
381 for( i=0; i<g_users_count; ++i ) 425 for (i = 0; i < g_users_count; ++i)
382 if( ( g_users[i].flags & UL_IN_MY_CHAN ) && !strncasecmp( g_users[i].nick, tmpstr, end ) ) { 426 if ((g_users[i].flags & UL_IN_MY_CHAN) &&
383 snprintf( tmpstr, TMPSTRSIZE, "%s:", g_users[i].nick ); 427 !strncasecmp(g_users[i].nick, tmpstr, end)) {
428 snprintf(tmpstr, TMPSTRSIZE, "%s:", g_users[i].nick);
384 result[++result_count] = strdup(tmpstr); 429 result[++result_count] = strdup(tmpstr);
385 } 430 }
386 431
387 /* Copy matches from personal dict to the end */ 432 /* Copy matches from personal dict to the end */
388 for( i=0; i<g_dict_len; ++i ) 433 for (i = 0; i < g_dict_len; ++i)
389 if( !strncasecmp( g_dict[i], tmpstr, end-start ) ) { 434 if (!strncasecmp(g_dict[i], tmpstr, end - start)) {
390 snprintf( tmpstr, TMPSTRSIZE, "%s:", g_dict[i] ); 435 snprintf(tmpstr, TMPSTRSIZE, "%s:", g_dict[i]);
391 result[++result_count] = strdup(tmpstr); 436 result[++result_count] = strdup(tmpstr);
392 } 437 }
393 438
394 /* Copy common prefix */ 439 /* Copy common prefix */
395 if( result_count ) result[0] = strndup(text, end); 440 if (result_count)
396 } else if( start != end ) { 441 result[0] = strndup(text, end);
442 } else if (start != end) {
397 /* Completion in the middle of the line most likely is a .m XY<TAB> 443 /* Completion in the middle of the line most likely is a .m XY<TAB>
398 and thus should complete all users, sorted alphabetically without 444 and thus should complete all users, sorted alphabetically without
399 preferences. */ 445 preferences. */
400 snprintf( tmpstr, end - start + 1, "%s", text ); 446 snprintf(tmpstr, end - start + 1, "%s", text);
401 if( ul_case_first ) 447 if (ul_case_first)
402 qsort( g_users, g_users_count, sizeof(user), ul_compare_middle_case ); 448 qsort(g_users, g_users_count, sizeof(user), ul_compare_middle_case);
403 else 449 else
404 qsort( g_users, g_users_count, sizeof(user), ul_compare_middle_ncase ); 450 qsort(g_users, g_users_count, sizeof(user), ul_compare_middle_ncase);
405 451
406 for( i=0; i<g_users_count; ++i ) 452 for (i = 0; i < g_users_count; ++i)
407 if( !strncasecmp( g_users[i].nick, tmpstr, end - start ) ) 453 if (!strncasecmp(g_users[i].nick, tmpstr, end - start))
408 result[++result_count] = strdup(g_users[i].nick); 454 result[++result_count] = strdup(g_users[i].nick);
409 455
410 /* Copy matches from personal dict to the end */ 456 /* Copy matches from personal dict to the end */
411 for( i=0; i<g_dict_len; ++i ) 457 for (i = 0; i < g_dict_len; ++i)
412 if( !strncasecmp( g_dict[i], tmpstr, end-start ) ) 458 if (!strncasecmp(g_dict[i], tmpstr, end - start))
413 result[++result_count] = strdup(g_dict[i]); 459 result[++result_count] = strdup(g_dict[i]);
414 460
415 /* Copy common prefix */ 461 /* Copy common prefix */
416 if( result_count ) result[0] = strndup(text, end - start); 462 if (result_count)
463 result[0] = strndup(text, end - start);
417 } /* else: completion of an empty word in the middle yields nothing */ 464 } /* else: completion of an empty word in the middle yields nothing */
418 465
419 if( !result_count ) { 466 if (!result_count) {
420 free( result ); 467 free(result);
421 result = 0; 468 result = 0;
422 } else 469 } else
423 result[++result_count] = 0; 470 result[++result_count] = 0;