1 /*
2 * IRC-II Copyright (C) 1990 Michael Sandroff and others,
3 * This file - Copyright (C) 1993,1995 Aaron Gifford
4 * This file written by Aaron Gifford and contributed to the EPIC
5 * project by Jeremy Nelson to whom it was contributed in Nov, 1993.
6 *
7 * Used with permission. See the COPYRIGHT file for copyright info.
8 */
9 /*
10 DATE OF THIS VERSION:
11 ---------------------
12 Sat Nov 27 23:00:20 MST 1993
13
14 NEW SINCE 20 NOV 1993:
15 ----------------------
16 Two new functions were added: GETMATCHES() and GETRMATCHES()
17
18 BUGS:
19 -----
20 I had a script that used these functions that caused ircII to crash
21 once or twice, but I have been unable to trace the cause or reproduce
22 the crash. I would appreciate any help or info if anyone else
23 experiences similar problems. This IS my first time using writing code
24 to work with ircII code.
25
26 ARGUMENTS:
27 ----------
28 array_name : A string of some sort (no spaces, case insensitive)
29 identifying an array, either an existing array, or a new array.
30
31 item_number : A number or index into the array. All array items are
32 numbered beginning at zero and continuing sequentially. The
33 item number can be an existing item of an existing array, a
34 new item in an existing array (if the previous greatest item
35 number was 5, then the new item number must be 6, maintaining
36 the sequence), or a new item (must be item zero) in a new array.
37 data_... : Basically any data you want. It is stored internally as a
38 character string, and in indexed (more to come) internally
39 using the standard C library function strcmp().
40
41 FUNCTIONS:
42 ----------
43 SETITEM(array_name item_number data_to_be_stored)
44 Use SETITEM to set an existing item of an existing array to a new value,
45 to create a new value in an existing array (see note about item_number),
46 or to create a new array (see note about item_number above).
47 RETURNS: 0 (zero) if it successfully sets and existing item in the array
48 1 if it successfully creates a new array
49 2 if it successfully adds a new item to an existing array
50 -1 if it was unable to find the array specified (item_number > 0)
51 -2 if it was unable to find the item in an existing array
52 (item_number was too large)
53
54 GETITEM(array_name item_number)
55 Use this to retrieve previously stored data.
56 RETURNS: the data requested
57 OR an empty string if the array did not exist or the item did not.
58
59 NUMITEMS(array_name)
60 RETURNS: the number of items in the array
61 OR zero if the array name is invalid. Useful for auto-adding to
62 an array:
63 alias ADDDATA {
64 if (SETITEM(my-array $NUMITEMS(my-array) $*) >= 0) {
65 echo ADDED DATA
66 } {
67 echo FAILED TO ADD DATA
68 }
69 }
70
71 DELITEM(array_name item_number)
72 This deletes the item requested from the array. If it is the last item
73 (item zero), it deletes the array. If there are items numbered higher
74 than this item, they will each be moved down. So if we had a 25 item
75 array called "MY-ARRAY" and deleted item 7, items 8 through 24 (remember
76 that a 25 item array is numbered 0 to 24) would be moved down and become
77 items 7 through 23.
78 RETURNS: Zero on success,
79 -1 if unable to find the array,
80 -2 if unable find the item.
81
82 MATCHITEM(array_name pattern)
83 Searches through the items in the array for the item that best matches
84 the pattern, much like the MATCH() function does.
85 RETURNS: zero or a positive number which is the item_number of the match
86 OR -1 if unable to find the array,
87 OR -2 if no match was found in the array
88
89 RMATCHITEM(array_name data_to_look_for)
90 This treats the items in the array as patterns, searching for the
91 pattern in the array that best matches the data_to_look_for, working
92 similarly to the RMATCH() function.
93 RETURNS: zero or a positive number which is the item_number of the match
94 OR -1 if unable to find the array,
95 OR -2 if no match was found in the array
96
97 GETMATCHES(array_name pattern)
98 Seeks all array items that match the pattern.
99 RETURNS: A string containing a space-separated list of item numbers of
100 array elements that match the pattern, or a null string if no
101 matches were found, or if the array was not found.
102
103 GETRMATCHES(array_name data_to_look_for)
104 Treats all array items as patterns, and seeks to find all patterns that
105 match the data_to_look_for.
106 RETURNS: A string containing a space-separated list of item numbers of
107 array elements that match the data, or a null string if no
108 matches were found, or if the array was not found.
109
110 FINDITEM(array_name data_to_search_for)
111 This does a binary search on the items stored in the array and returns
112 the item number of the data. It is an EXACT MATCH search. It is highly
113 case sensitive, using C's strcmp() and not IRCII's caseless comparison
114 functions. I did it this way, because I needed it, so there! ;)
115 RETURNS: zero or a positive number on success -- this number IS the
116 item_number of the first match it found
117 OR -1 if unable to find the array,
118 OR -2 if the item was not found in the array.
119
120 IGETITEM(array_name index_number)
121 This is exactly like GETITEM() except it uses a index number in the same
122 range as the item_number's. It returns the item that corresponds to the
123 internal alphabetized index that these functions maintain. Thus if you
124 access items 0 to 24 of "MY-ARRAY" with this function, you would observe
125 that the items returned came in an almost alphabetized manner. They
126 would not be truly alphabetized because the ordering is done using
127 strcmp() which is case sensitive.
128 RETURNS: the data to which the index refers
129 OR an empty string on failure to find the array or index.
130
131 INDEXTOITEM(array_name index_number)
132 This converts an index_number to an item_number.
133 RETURNS: the item_number that corresponds to the index_number for
134 the array
135 OR -1 if unable to find the array,
136 OR -2 if the index_number was invalid
137
138 ITEMTOINDEX(array_name item_number)
139 This converts an item_number to an index_number.
140 RETURNS: the index_number that corresponds to the item_number for
141 the array
142 OR -1 if unable to find the array,
143 OR -2 if the item_number was invalid
144
145 DELARRAY(array_name)
146 This deletes all items in an array.
147 RETURNS: zero on success, -1 if it couldn't find the array.
148
149 NUMARRAYS()
150 RETURNS: the number of arrays that currently exist.
151
152 GETARRAYS()
153 RETURNS: a string consisting of all the names of all the arrays
154 separated by spaces.
155
156 Thanks,
157 Aaron Gifford
158 Karll on IRC
159 <agifford@sci.dixie.edu>
160
161 */
162 /*
163 * FILE: alias.c
164 * WRITTEN BY: Aaron Gifford (Karll on IRC)
165 * DATE: Sat Nov 27 23:00:20 MST 1993
166 */
167
168 #include "irc.h"
169 static char cvsrevision[] = "$Id: array.c 227 2013-02-16 08:11:07Z keaston $";
170 CVS_REVISION(array_c)
171
172 #include "array.h"
173 #include "ircaux.h"
174 #include "output.h"
175 #undef index
176
177 #define MAIN_SOURCE
178 #include "modval.h"
179
180 #define ARRAY_THRESHOLD 100
181
182 typedef struct an_array_struct {
183 char **item;
184 long *index;
185 long size;
186 } an_array;
187
188 static an_array array_info = {
189 NULL,
190 NULL,
191 0L
192 };
193
194 static an_array *array_array = NULL;
195
196 /*
197 * find_item() does a binary search of array.item[] using array.index[]
198 * to find an exact match of the string *find. If found, it returns the item
199 * number (array.item[item_number]) of the match. Otherwise, it returns a
200 * negative number. The negative number, if made positive again, and then
201 * having 1 subtracted from it, will be the item_number where the string *find
202 * should be inserted into the array.item[]. The function_setitem() makes use
203 * of this attribute.
204 */
find_item(an_array array,char * find)205 extern long find_item (an_array array, char *find)
206 {
207 long top, bottom, key, cmp;
208
209 top = array.size - 1;
210 bottom = 0;
211
212 while (top >= bottom)
213 {
214 key = (top - bottom) / 2 + bottom;
215 cmp = strcmp(find, array.item[array.index[key]]);
216 if (cmp == 0)
217 return key;
218 if (cmp < 0)
219 top = key - 1;
220 else
221 bottom = key + 1;
222 }
223 return -bottom - 1;
224 }
225
226 /*
227 * insert_index() takes a valid index (newIndex) and inserts it into the array
228 * **index, then increments the *size of the index array.
229 */
insert_index(long ** index,long * size,long newIndex)230 extern void insert_index (long **index, long *size, long newIndex)
231 {
232 long cnt;
233
234 if (*size)
235 RESIZE(*index, long, *size + 1);
236 else
237 {
238 *index = (long *)new_malloc(sizeof(long));
239 newIndex = 0;
240 }
241
242 for (cnt = *size; cnt > newIndex; cnt--)
243 (*index)[cnt] = (*index)[cnt - 1];
244 (*index)[newIndex] = *size;
245 (*size)++;
246 }
247
248 /*
249 * move_index() moves the array.index[] up or down to make room for new entries
250 * or to clean up so an entry can be deleted.
251 */
move_index(an_array * array,long oldindex,long newindex)252 extern void move_index (an_array *array, long oldindex, long newindex)
253 {
254 long temp;
255
256 if (newindex > oldindex)
257 newindex--;
258 if (newindex == oldindex)
259 return;
260
261 temp = array->index[oldindex];
262
263 if (oldindex < newindex)
264 for (; oldindex < newindex; oldindex++)
265 array->index[oldindex] = array->index[oldindex + 1];
266 else
267 for(; oldindex > newindex; oldindex--)
268 array->index[oldindex] = array->index[oldindex - 1];
269
270 array->index[newindex] = temp;
271 }
272
273 /*
274 * find_index() attempts to take an item and discover the index number
275 * that refers to it. find_index() assumes that find_item() WILL always return
276 * a positive or zero result (be successful) because find_index() assumes that
277 * the item is valid, and thus a find will be successful. I don't know what
278 * value ARRAY_THRESHOLD ought to be. I figured someone smarter than I am
279 * could figure it out and tell me or tell me to abandon the entire idea.
280 */
find_index(an_array * array,long item)281 extern long find_index (an_array *array, long item)
282 {
283 long i = 0;
284
285 if (array->size >= ARRAY_THRESHOLD)
286 {
287 i = find_item(*array, array->item[item]);
288 while (i >= 0 && !strcmp(array->item[array->index[i]], array->item[item]))
289 i--;
290 i++;
291 }
292 while(array->index[i] != item && i < array->size)
293 i++;
294
295 if (i == array->size)
296 say("ERROR in find_index()");
297 return i;
298 }
299
300 /*
301 * get_array() searches and finds the array referenced by *name. It returns
302 * a pointer to the array, or a null pointer on failure to find it.
303 */
get_array(char * name)304 extern an_array * get_array (char *name)
305 {
306 long index;
307
308 if (array_info.size && *name)
309 {
310 upper(name);
311 if ((index = find_item(array_info, name)) >= 0)
312 return &array_array[array_info.index[index]];
313 }
314 return NULL;
315 }
316
317
318 /*
319 * delete_array() deletes the contents of an entire array. It assumes that
320 * find_item(array_info, name) will succeed and return a valid zero or positive
321 * value.
322 */
delete_array(char * name)323 extern void delete_array (char *name)
324 {
325 char **ptr;
326 long cnt;
327 long index;
328 long item;
329 an_array *array;
330
331 index = find_item(array_info, name);
332 item = array_info.index[index];
333 array = &array_array[item];
334 for (ptr=array->item, cnt=0; cnt < array->size; cnt++, ptr++)
335 new_free((char **)ptr);
336 new_free((char **)&array->item);
337 new_free((char **)&array->index);
338
339 if (array_info.size > 1)
340 {
341 for(cnt = 0; cnt < array_info.size; cnt++)
342 if (array_info.index[cnt] > item)
343 (array_info.index[cnt])--;
344 move_index(&array_info, index, array_info.size);
345 array_info.size--;
346 for(ptr=&array_info.item[item], cnt=item; cnt < array_info.size; cnt++, ptr++, array++)
347 {
348 *ptr = *(ptr + 1);
349 *array = *(array + 1);
350 }
351 RESIZE(array_info.item, char *, array_info.size);
352 RESIZE(array_info.index, long, array_info.size);
353 RESIZE(array_array, an_array, array_info.size);
354 }
355 else
356 {
357 new_free((char **)&array_info.item);
358 new_free((char **)&array_info.index);
359 new_free((char **)&array_array);
360 array_info.size = 0;
361 }
362 }
363
delete_all_arrays(void)364 void delete_all_arrays(void)
365 {
366 char **ptr;
367 long index;
368 an_array *array;
369 #if 0
370 m_s3cat(&result, space, array_info.item[array_info.index[index]]);
371 #endif
372 for (index = 0; index < array_info.size; index++)
373 {
374 array = &array_array[index];
375 ptr = array->item;
376 while (array->size > 0)
377 {
378 new_free((char **)ptr);
379 ptr++;
380 array->size--;
381 }
382 new_free((char **)&array->item);
383 new_free((char **)&array->index);
384 }
385 for (index = 0; index < array_info.size; index++)
386 {
387 ptr = (char **)&array_info.item[index];
388 new_free(ptr);
389 ptr++;
390 }
391 new_free((char **)&array_info.item);
392 new_free((char **)&array_info.index);
393 new_free((char **)&array_array);
394 array_info.size = 0;
395 }
396
397 /*
398 * Now for the actual alias functions
399 * ==================================
400 */
401
402 /*
403 * These are the same ones found in alias.c
404 */
405 #define EMPTY empty_string
406 #define RETURN_EMPTY return m_strdup(EMPTY)
407 #define RETURN_IF_EMPTY(x) if (empty( x )) RETURN_EMPTY
408 #define GET_INT_ARG(x, y) {RETURN_IF_EMPTY(y); x = my_atol(safe_new_next_arg(y, &y));}
409 #define GET_FLOAT_ARG(x, y) {RETURN_IF_EMPTY(y); x = atof(safe_new_next_arg(y, &y));}
410 #define GET_STR_ARG(x, y) {RETURN_IF_EMPTY(y); x = new_next_arg(y, &y);RETURN_IF_EMPTY(x);}
411 #define RETURN_STR(x) return m_strdup(x ? x : EMPTY);
412 #define RETURN_INT(x) return m_strdup(ltoa(x));
413
414 /*
415 * function_matchitem() attempts to match a pattern to the contents of an array
416 * RETURNS -1 if it cannot find the array, or -2 if no matches occur
417 */
BUILT_IN_FUNCTION(function_matchitem)418 BUILT_IN_FUNCTION(function_matchitem)
419 {
420 char *name;
421 long index;
422 an_array *array;
423 long current_match;
424 long best_match = 0;
425 long match = -1;
426
427 if ((name = next_arg(input, &input)) && (array = get_array(name)))
428 {
429 match = -2;
430 if (*input)
431 {
432 for (index = 0; index < array->size; index++)
433 {
434 if ((current_match = wild_match(input, array->item[index])) > best_match)
435 {
436 match = index;
437 best_match = current_match;
438 }
439 }
440 }
441 }
442
443 RETURN_INT(match);
444 }
445
BUILT_IN_FUNCTION(function_igetmatches)446 BUILT_IN_FUNCTION(function_igetmatches)
447 {
448 char *result = NULL;
449 char *name = NULL;
450 long item;
451 an_array *array;
452
453 if ((name = next_arg(input, &input)) &&
454 (array = get_array(name)) && *input)
455 {
456 if (*input)
457 {
458 for (item = 0; item < array->size; item++)
459 {
460 if (wild_match(input, array->item[item]) > 0)
461 m_s3cat(&result, space, ltoa(find_index(array, item)));
462 }
463 }
464 }
465
466 if (!result)
467 RETURN_EMPTY;
468
469 return result;
470 }
471
472 /*
473 * function_listarray() attempts to list the contents of an array
474 * RETURNS "" if it cannot find the array
475 */
BUILT_IN_FUNCTION(function_listarray)476 BUILT_IN_FUNCTION(function_listarray)
477 {
478 char *name;
479 an_array *array;
480 long index;
481 char *result = NULL;
482
483 if ((name = next_arg(input, &input)) && (array = get_array(name)))
484 {
485 for (index = 0; index < array->size; index++)
486 m_s3cat(&result, space, array->item[index]);
487 }
488 return result ? result : m_strdup(empty_string);
489 }
490
491 /*
492 * function_getmatches() attempts to match a pattern to the contents of an
493 * array and returns a list of item_numbers of all items that match the pattern
494 * or it returns an empty string if not items matches or if the array was not
495 * found.
496 */
BUILT_IN_FUNCTION(function_getmatches)497 BUILT_IN_FUNCTION(function_getmatches)
498 {
499 char *result = NULL;
500 char *name = NULL;
501 long index;
502 an_array *array;
503
504 if ((name = next_arg(input, &input)) &&
505 (array = get_array(name)) && *input)
506 {
507 if (*input)
508 {
509 for (index = 0; index < array->size; index++)
510 {
511 if (wild_match(input, array->item[index]) > 0)
512 m_s3cat(&result, space, ltoa(index));
513 }
514 }
515 }
516 if (!result)
517 RETURN_EMPTY;
518 return result;
519 }
520
521 /*
522 * function_rmatchitem() attempts to match the input text with an array of
523 * patterns, much like RMATCH()
524 * RETURNS -1 if it cannot find the array, or -2 if no matches occur
525 */
BUILT_IN_FUNCTION(function_rmatchitem)526 BUILT_IN_FUNCTION(function_rmatchitem)
527 {
528 char *name = NULL;
529 long index;
530 an_array *array;
531 long current_match;
532 long best_match = 0;
533 long match = -1;
534
535 if ((name = next_arg(input, &input)) && (array = get_array(name)))
536 {
537 match = -2;
538 if (*input)
539 {
540 for (index = 0; index < array->size; index++)
541 {
542 if ((current_match = wild_match(array->item[index], input)) > best_match)
543 {
544 match = index;
545 best_match = current_match;
546 }
547 }
548 }
549 }
550 RETURN_INT(match)
551 }
552
553 /*
554 * function_getrmatches() attempts to match the input text with an array of
555 * patterns, and returns a list of item_numbers of all patterns that match the
556 * given text, or it returns a null string if no matches occur or if the array
557 * was not found.
558 */
BUILT_IN_FUNCTION(function_getrmatches)559 BUILT_IN_FUNCTION(function_getrmatches)
560 {
561 char *result = NULL;
562 char *name = NULL;
563 long index;
564 an_array *array;
565
566 if ((name = next_arg(input, &input)) && (array = get_array(name)))
567 {
568 if (*input)
569 {
570 for (index = 0; index < array->size; index++)
571 {
572 if (wild_match(array->item[index], input) > 0)
573 m_s3cat(&result, space, ltoa(index));
574 }
575 }
576 }
577
578 if (!result)
579 RETURN_EMPTY;
580 return result;
581 }
582
583 /*
584 * function_numitems() returns the number of items in an array, or -1 if unable
585 * to find the array
586 */
BUILT_IN_FUNCTION(function_numitems)587 BUILT_IN_FUNCTION(function_numitems)
588 {
589 char *name = NULL;
590 an_array *array;
591 long items = 0;
592
593 if ((name = next_arg(input, &input)) && (array = get_array(name)))
594 items = array->size;
595
596 RETURN_INT(items);
597 }
598
599 /*
600 * function_getitem() returns the value of the specified item of an array, or
601 * returns an empty string on failure to find the item or array
602 */
BUILT_IN_FUNCTION(function_getitem)603 BUILT_IN_FUNCTION(function_getitem)
604 {
605 char *name = NULL;
606 char *itemstr = NULL;
607 long item;
608 an_array *array;
609 char *found = NULL;
610
611 if ((name = next_arg(input, &input)) && (array = get_array(name)))
612 {
613 if ((itemstr = next_arg(input, &input)))
614 {
615 item = my_atol(itemstr);
616 if (item >= 0 && item < array->size)
617 found = array->item[item];
618 }
619 }
620 RETURN_STR(found);
621 }
622
623 /*
624 * function_setitem() sets an item of an array to a value, or creates a new
625 * array if the array doesn not already exist and the item number is zero, or
626 * it adds a new item to an existing array if the item number is one more than
627 * the prevously largest item number in the array.
628 * RETURNS: 0 on success
629 * 1 on success if a new item was added to an existing array
630 * 2 on success if a new array was created and item zero was set
631 * -1 if it is unable to find the array (and item number was not zero)
632 * -2 if it was unable to find the item (item < 0 or item was greater
633 * than 1 + the prevous maximum item number
634 */
BUILT_IN_FUNCTION(function_setitem)635 BUILT_IN_FUNCTION(function_setitem)
636 {
637 char *name = NULL;
638 char *itemstr = NULL;
639 long item;
640 long index = 0;
641 long oldindex;
642 an_array *array;
643 int result = -1;
644
645 if ((name = next_arg(input, &input)))
646 {
647 if (strlen(name) && (itemstr = next_arg(input, &input)))
648 {
649 item = my_atol(itemstr);
650 if (item >= 0)
651 {
652 upper(name);
653 if (array_info.size && ((index = find_item(array_info, name)) >= 0))
654 {
655 array = &array_array[array_info.index[index]];
656 result = -2;
657 if (item < array->size)
658 {
659 oldindex = find_index(array, item);
660 index = find_item(*array, input);
661 index = (index >= 0) ? index : (-index) - 1;
662 move_index(array, oldindex, index);
663 new_free(&array->item[item]);
664 malloc_strcpy(&array->item[item], input);
665 result = 0;
666 }
667 else if (item == array->size)
668 {
669 RESIZE(array->item, char *, (array->size + 1));
670 array->item[item] = NULL;
671 malloc_strcpy(&array->item[item], input);
672 index = find_item(*array, input);
673 index = (index >= 0) ? index : (-index) - 1;
674 insert_index(&array->index, &array->size, index);
675 result = 2;
676 }
677 }
678 else
679 {
680 if (item == 0)
681 {
682 if (array_info.size)
683 RESIZE(array_array, an_array, (array_info.size + 1));
684 else
685 array_array = (an_array*)new_malloc(sizeof(an_array));
686 array = &array_array[array_info.size];
687 array->size = 1;
688 array->item = (char **)new_malloc(sizeof(char *));
689 array->index = (long *)new_malloc(sizeof(long));
690 array->item[0] = (char*) 0;
691 array->index[0] = 0;
692 malloc_strcpy(&array->item[0], input);
693 if (array_info.size)
694 RESIZE(array_info.item, char *, (array_info.size + 1));
695 else
696 array_info.item = (char **)new_malloc(sizeof(char *));
697 array_info.item[array_info.size] = NULL;
698 malloc_strcpy(&array_info.item[array_info.size], name);
699 insert_index(&array_info.index, &array_info.size, (-index) - 1);
700 result = 1;
701 }
702 }
703 }
704 }
705 }
706 RETURN_INT(result);
707 }
708
709 /*
710 * function_getarrays() returns a string containg the names of all currently
711 * existing arrays separated by spaces
712 */
BUILT_IN_FUNCTION(function_getarrays)713 BUILT_IN_FUNCTION(function_getarrays)
714 {
715 long index;
716 char *result = NULL;
717
718 for (index = 0; index < array_info.size; index++)
719 if (!input || !*input || wild_match(input, array_info.item[array_info.index[index]]))
720 m_s3cat(&result, space, array_info.item[array_info.index[index]]);
721
722 if (!result)
723 RETURN_EMPTY;
724
725 return result;
726 }
727
728 /*
729 * function_numarrays() returns the number of currently existing arrays
730 */
BUILT_IN_FUNCTION(function_numarrays)731 BUILT_IN_FUNCTION(function_numarrays)
732 {
733 RETURN_INT(array_info.size)
734 }
735
736 /*
737 * function_finditem() does a binary search and returns the item number of
738 * the string that exactly matches the string searched for, or it returns
739 * -1 if unable to find the array, or -2 if unable to find the item.
740 */
BUILT_IN_FUNCTION(function_finditem)741 BUILT_IN_FUNCTION(function_finditem)
742 {
743 char *name = NULL;
744 an_array *array;
745 long item = -1;
746
747 if ((name = next_arg(input, &input)) && (array = get_array(name)))
748 {
749 if (*input)
750 {
751 item = find_item(*array, input);
752 item = (item >= 0) ? array->index[item] : -2;
753 }
754 }
755 RETURN_INT(item)
756 }
757
758 /*
759 * function_ifinditem() does a binary search and returns the index number of
760 * the string that exactly matches the string searched for, or it returns
761 * -1 if unable to find the array, or -2 if unable to find the item.
762 */
BUILT_IN_FUNCTION(function_ifinditem)763 BUILT_IN_FUNCTION(function_ifinditem)
764 {
765 char *name = NULL;
766 an_array *array;
767 long item = -1;
768
769 if ((name = next_arg(input, &input)) && (array = get_array(name)))
770 {
771 if (*input)
772 {
773 if ((item = find_item(*array, input)) < 0)
774 item = -2;
775 }
776 }
777 RETURN_INT(item)
778 }
779
780 /*
781 * function_igetitem() returns the item referred to by the passed-in index
782 * or returns an empty string if unable to find the array or if the index was
783 * invalid.
784 */
BUILT_IN_FUNCTION(function_igetitem)785 BUILT_IN_FUNCTION(function_igetitem)
786 {
787 char *name = NULL;
788 char *itemstr = NULL;
789 long item;
790 an_array *array;
791 char *found = NULL;
792
793 if ((name = next_arg(input, &input)) && (array = get_array(name)))
794 {
795 if ((itemstr = next_arg(input, &input)))
796 {
797 item = my_atol(itemstr);
798 if (item >= 0 && item < array->size)
799 found = array->item[array->index[item]];
800 }
801 }
802 RETURN_STR(found)
803 }
804
805 /*
806 * function_indextoitem() converts an index number to an item number for the
807 * specified array. It returns a valid item number, or -1 if unable to find
808 * the array, or -2 if the index was invalid.
809 */
BUILT_IN_FUNCTION(function_indextoitem)810 BUILT_IN_FUNCTION(function_indextoitem)
811 {
812 char *name = NULL;
813 char *itemstr = NULL;
814 long item;
815 an_array *array;
816 long found = -1;
817
818 if ((name = next_arg(input, &input)) && (array = get_array(name)))
819 {
820 found = -2;
821 if ((itemstr = next_arg(input, &input)))
822 {
823 item = my_atol(itemstr);
824 if (item >= 0 && item < array->size)
825 found = array->index[item];
826 }
827 }
828 RETURN_INT(found)
829 }
830
831 /*
832 * function_itemtoindex() takes an item number and searches for the index that
833 * refers to the item. It returns the index number, or -1 if unable to find
834 * the array, or -2 if the item was invalid.
835 */
BUILT_IN_FUNCTION(function_itemtoindex)836 BUILT_IN_FUNCTION(function_itemtoindex)
837 {
838 char *name;
839 char *itemstr;
840 long item;
841 an_array *array;
842 long found = -1;
843
844 if ((name = next_arg(input, &input)) && (array = get_array(name)))
845 {
846 found = -2;
847 if ((itemstr = next_arg(input, &input)))
848 {
849 item = my_atol(itemstr);
850 if (item >= 0 && item < array->size)
851 found = find_index(array, item);
852 }
853 }
854 RETURN_INT(found)
855 }
856
857 /*
858 * function_delitem() deletes an item of an array and moves the contents of the
859 * array that were stored "above" the item down by one. It returns 0 (zero)
860 * on success, -1 if unable to find the array, -2 if unable to find the item.
861 * Also, if the item is the last item in the array, it deletes the array.
862 */
BUILT_IN_FUNCTION(function_delitem)863 BUILT_IN_FUNCTION(function_delitem)
864 {
865 char *name;
866 char *itemstr;
867 char **strptr;
868 long item;
869 long cnt;
870 long oldindex;
871 an_array *array;
872 long found = -1;
873
874 if ((name = next_arg(input, &input)) && (array = get_array(name)))
875 {
876 found = -2;
877 if ((itemstr = next_arg(input, &input)))
878 {
879 item = my_atol(itemstr);
880 if (item >= 0 && item < array->size)
881 {
882 if (array->size == 1)
883 delete_array(name);
884 else
885 {
886 oldindex = find_index(array, item);
887 for(cnt = 0; cnt < array->size; cnt++)
888 if (array->index[cnt] > item)
889 (array->index[cnt])--;
890 move_index(array, oldindex, array->size);
891 new_free(&array->item[item]);
892 array->size--;
893 for(strptr=&(array->item[item]), cnt=item; cnt < array->size; cnt++, strptr++)
894 *strptr = *(strptr + 1);
895 RESIZE(array->item, char *, array->size);
896 RESIZE(array->index, long, array->size);
897 }
898 found = 0;
899 }
900 }
901 }
902 RETURN_INT(found)
903 }
904
905 /*
906 * function_delarray() deletes the entire contents of the array using the
907 * delete_array() function above. It returns 0 on success, -1 on failure.
908 */
BUILT_IN_FUNCTION(function_delarray)909 BUILT_IN_FUNCTION(function_delarray)
910 {
911 char *name;
912 long found = -1;
913
914 if ((name = next_arg(input, &input)) && (get_array(name)))
915 {
916 delete_array(name);
917 found = 0;
918 }
919 RETURN_INT(found)
920 }
921 /*
922 * function_ifindfirst() returns the first index of an exact match with the
923 * search string, or returns -2 if unable to find the array, or -1 if unable
924 * to find any matches.
925 */
BUILT_IN_FUNCTION(function_ifindfirst)926 BUILT_IN_FUNCTION(function_ifindfirst)
927 {
928 char *name;
929 an_array *array;
930 long item = -1;
931
932 if ((name = next_arg(input, &input)) && (array = get_array(name)))
933 {
934 if (*input)
935 {
936 if ((item = find_item(*array, input)) < 0)
937 item = -2;
938 else
939 {
940 while (item >= 0 && !strcmp(array->item[array->index[item]], input))
941 item--;
942 item++;
943 }
944 }
945 }
946 RETURN_INT(item)
947 }
948
949 /*
950 * Given an array name with various strings in it, we wild_match() against
951 * the elements within the array. This allows parsing using % and *
952 * for wildcards. We return only the best match from the array, unlike
953 * getmatch() which returns ALL the matching items.
954 */
955
BUILT_IN_FUNCTION(function_gettmatch)956 BUILT_IN_FUNCTION(function_gettmatch)
957 {
958 char *name;
959 an_array *array;
960 char *ret = NULL;
961 #if 0
962 <shade> gettmatch(users % user@host *) would match the userhost mask in the
963 second word of the array
964 #endif
965 if ((name = next_arg(input, &input)) && (array = get_array(name)))
966 {
967 if (*input)
968 {
969 int index, current_match;
970 int best_match = 0;
971 int match = -1;
972 for (index = 0; index < array->size; index++)
973 {
974 if ((current_match = wild_match(input, array->item[index])) > best_match)
975 {
976 match = index;
977 best_match = current_match;
978 }
979 }
980 if (match != -1)
981 ret = array->item[match];
982
983 }
984 }
985 RETURN_STR(ret);
986 }
987
BUILT_IN_FUNCTION(function_igetrmatches)988 BUILT_IN_FUNCTION(function_igetrmatches)
989 {
990 char *result = (char *) 0;
991 char *name = (char *) 0;
992 long item;
993 an_array *array;
994
995 if ((name = next_arg(input, &input)) &&
996 (array = get_array(name)) && *input)
997 {
998 if (*input)
999 {
1000 for (item = 0; item < array->size; item++)
1001 {
1002 if (wild_match(array->item[item], input) > 0)
1003 m_s3cat(&result, space, ltoa(find_index(array, item)));
1004 }
1005 }
1006 }
1007
1008 if (!result)
1009 RETURN_EMPTY;
1010
1011 return result;
1012 }
1013