Initial import (again)
[srvx.git] / src / modules.c
1 /* modules.c - Compiled-in module support
2  * Copyright 2002-2003 srvx Development Team
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.  Important limitations are
8  * listed in the COPYING file that accompanies this software.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, email srvx-maintainers@srvx.net.
17  */
18
19 #include "log.h"
20 #include "modules.h"
21
22 enum init_state {
23     UNINIT,
24     WORKING,
25     BROKEN,
26     INITED,
27     DONE
28 };
29
30 struct cmodule {
31     const char *name;
32     int (*init_func)(void);
33     int (*finalize_func)(void);
34     const char **deps;
35     enum init_state state;
36 };
37
38 #define WITH_MODULE(x) extern int x##_init(void); extern int x##_finalize(void); extern const char *x##_module_deps[];
39 #include "modules-list.h"
40 #undef WITH_MODULE
41
42 static struct cmodule cmodules[] = {
43 #define WITH_MODULE(x) { #x, x##_init, x##_finalize, x##_module_deps, UNINIT },
44 #include "modules-list.h"
45 #undef WITH_MODULE
46     /* Placeholder at end of array */
47     { NULL, NULL, NULL, NULL, UNINIT }
48 };
49
50 static int
51 modules_bsearch(const void *a, const void *b) {
52     const char *key = a;
53     const struct cmodule *cmod = b;
54     return irccasecmp(key, cmod->name);
55 }
56
57 static int
58 modules_qsort(const void *a, const void *b) {
59     const struct cmodule *ca = a, *cb = b;
60     return irccasecmp(ca->name, cb->name);
61 }
62
63 static int
64 module_init(struct cmodule *cmod, int final) {
65     unsigned int ii;
66     struct cmodule *dep;
67
68     switch (cmod->state) {
69     case UNINIT: break;
70     case INITED: if (!final) return 1; break;
71     case DONE:   return 1;
72     case BROKEN: return 0;
73     case WORKING:
74         log_module(MAIN_LOG, LOG_ERROR, "Tried to recursively enable code module %s.", cmod->name);
75         return 0;
76     }
77     cmod->state = WORKING;
78     for (ii=0; cmod->deps[ii]; ++ii) {
79         dep = bsearch(cmod->deps[ii], cmodules, ArrayLength(cmodules)-1, sizeof(cmodules[0]), modules_bsearch);
80         if (!dep) {
81             log_module(MAIN_LOG, LOG_ERROR, "Code module %s depends on unknown module %s.", cmod->name, cmod->deps[ii]);
82             cmod->state = BROKEN;
83             return 0;
84         }
85         if (!module_init(dep, final)) {
86             log_module(MAIN_LOG, LOG_ERROR, "Failed to initialize dependency %s of code module %s.", dep->name, cmod->name);
87             cmod->state = BROKEN;
88             return 0;
89         }
90     }
91     if (final) {
92         if (!cmod->finalize_func()) {
93             log_module(MAIN_LOG, LOG_ERROR, "Failed to finalize code module %s.", cmod->name);
94             cmod->state = BROKEN;
95             return 0;
96         }
97         cmod->state = DONE;
98         return 1;
99     } else {
100         if (!cmod->init_func()) {
101             log_module(MAIN_LOG, LOG_ERROR, "Failed to initialize code module %s.", cmod->name);
102             cmod->state = BROKEN;
103             return 0;
104         }
105         cmod->state = INITED;
106         return 1;
107     }
108 }
109
110 void
111 modules_init(void) {
112     unsigned int ii;
113
114     qsort(cmodules, ArrayLength(cmodules)-1, sizeof(cmodules[0]), modules_qsort);
115     for (ii=0; cmodules[ii].name; ++ii) {
116         if (cmodules[ii].state != UNINIT) continue;
117         module_init(cmodules + ii, 0);
118         if (cmodules[ii].state != INITED) {
119             log_module(MAIN_LOG, LOG_WARNING, "Code module %s not properly initialized.", cmodules[ii].name);
120         }
121     }
122 }
123
124 void
125 modules_finalize(void) {
126     unsigned int ii;
127
128     for (ii=0; cmodules[ii].name; ++ii) {
129         if (cmodules[ii].state != INITED) continue;
130         module_init(cmodules + ii, 1);
131         if (cmodules[ii].state != DONE) {
132             log_module(MAIN_LOG, LOG_WARNING, "Code module %s not properly finalized.", cmodules[ii].name);
133         }
134     }
135 }