1 #include <stdlib.h>             /* bsearch           */
2 #include <stdio.h>              /* fprintf to stderr */
3 #include <string.h>             /* strcmp            */
4 
5 #include "findtok.h"
6 
7 /* This function fills in a structure of type token_list_t based on a token_t
8    array. The token_list_t structure contains some internal control data used
9    by find_token. The last element of the token_t array must have a NULL
10    pointer in the "token" field.
11 
12    The main function of this function is to a) count the number of tokens and b)
13    make sure that the array of tokens that the programmer supplies
14    to us is sorted so that we can later use bsearch on it.
15 
16    If the array is not sorted, we simply print a warning to stderr.
17    We do NOT resort the array in this case, because normally the
18    order of magnitude of keywords in this array is in the same order
19    of magnitude of keywords that will be in the config file to
20    parse, so that sorting of the array of the program start would
21    not yield any net performance gain.  The programmer should supply
22    us with an already sorted list of keywords instead!
23 */
24 
make_token_list(token_list_t * dst,token_t * src)25 void make_token_list (token_list_t *dst, token_t *src)
26 {
27     int i;
28 
29     dst->tokens = src; dst->ntokens = 0; dst->bsearchable = 1;
30 
31     if (src[0].token == NULL)
32         return;                 /* nothing to do for an empty list */
33 
34     for (i = 1; src[i].token != NULL; i++)
35     {
36         if (dst->bsearchable && strcmp(src[i-1].token, src[i].token) >= 0)
37         {
38             fprintf (stderr, "Warning: Token array is not bsearchable. This "
39                      "will result in a performance\npenalty. The offending "
40                      "token is: %s\n", src[i].token);
41             dst->bsearchable = 0;
42         }
43     }
44 
45     dst->ntokens = i;
46 }
47 
token_compare(const void * a,const void * b)48 static int token_compare (const void *a, const void *b)
49 {
50     const token_t *pa = (const token_t *)a;
51     const token_t *pb = (const token_t *)b;
52 
53     return strcmp(pa->token, pb->token);
54 }
55 
56 
57 /* This function returns the token ID based on a keyword, or -1 or
58    the keyword is not found in the token list. */
59 
find_token(token_list_t * tokenlist,const char * key)60 int find_token(token_list_t *tokenlist, const char *key)
61 {
62     int i;
63     token_t keytoken, *result;
64 
65                                 /* fall back code when the array is not
66                                    sorted */
67     if (!tokenlist->bsearchable)
68     {
69         for (i = 0; i < tokenlist->ntokens; i++)
70         {
71             if (!strcmp(tokenlist->tokens[i].token, key))
72                 return tokenlist->tokens[i].id;
73         }
74         return -1;
75     }
76                                 /* bsearch code */
77     keytoken.token = key;
78     keytoken.id    = -1;
79 
80     result = bsearch(&keytoken, tokenlist->tokens, tokenlist->ntokens,
81                      sizeof(token_t), token_compare);
82 
83     if (result == NULL)
84         return -1;
85 
86     return result->id;
87 }
88 
89 #if 0
90 
91 /* This code is an example on how to use the routines from this file */
92 
93 #include "findtok.h"
94 
95 enum { ID_LINK=0, ID_LOGFILE, ID_NODELIST, ID_SYSOP };
96 
97 token_t mytokens[]=
98 {
99     { "link", ID_LINK },
100     { "logfile", ID_LOGFILE },
101     { "nodelist", ID_NODELIST },
102     { "sysop", ID_SYSOP },
103     { NULL, -1 }
104 };
105 
106 token_list_t mytokenlist;
107 
108 int main(void)
109 {
110     make_token_list(&mytokenlist, mytokens);
111     switch (find_token(&mytokenlist, "logfile"))
112     {
113     case ID_LINK:     printf ("link\n"); break;
114     case ID_LOGFILE:  printf ("logfile\n"); break;
115     case ID_NODELIST: printf ("nodelist\n"); break;
116     case ID_SYSOP:    printf ("sysop\n"); break;
117     default:          printf ("unknown keyword\n");
118     }
119     return 0;
120 }
121 
122 #endif
123