Added SILC Thread Queue API
[crypto.git] / apps / irssi / src / fe-common / core / fe-help.c
1 /*
2  fe-help.c : irssi
3
4     Copyright (C) 1999-2001 Timo Sirainen
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "module.h"
22 #include "signals.h"
23 #include "commands.h"
24 #include "levels.h"
25 #include "misc.h"
26 #include "line-split.h"
27 #include "settings.h"
28
29 #include "printtext.h"
30 #include "formats.h"
31
32 static int commands_equal(COMMAND_REC *rec, COMMAND_REC *rec2)
33 {
34         int i;
35
36         if (rec->category == NULL && rec2->category != NULL)
37                 return -1;
38         if (rec2->category == NULL && rec->category != NULL)
39                 return 1;
40         if (rec->category != NULL && rec2->category != NULL) {
41                 i = strcmp(rec->category, rec2->category);
42                 if (i != 0)
43                         return i;
44         }
45
46         return strcmp(rec->cmd, rec2->cmd);
47 }
48
49 static int get_cmd_length(void *data)
50 {
51         return strlen(((COMMAND_REC *) data)->cmd);
52 }
53
54 static void help_category(GSList *cmdlist, int items)
55 {
56         WINDOW_REC *window;
57         TEXT_DEST_REC dest;
58         GString *str;
59         GSList *tmp;
60         int *columns, cols, rows, col, row, last_col_rows, max_width;
61         char *linebuf, *format, *stripped;
62
63         window = window_find_closest(NULL, NULL, MSGLEVEL_CLIENTCRAP);
64         max_width = window->width;
65
66         /* remove width of timestamp from max_width */
67         format_create_dest(&dest, NULL, NULL, MSGLEVEL_CLIENTCRAP, NULL);
68         format = format_get_line_start(current_theme, &dest, time(NULL));
69         if (format != NULL) {
70                 stripped = strip_codes(format);
71                 max_width -= strlen(stripped);
72                 g_free(stripped);
73                 g_free(format);
74         }
75
76         /* calculate columns */
77         cols = get_max_column_count(cmdlist, get_cmd_length,
78                                     max_width, 6, 1, 3, &columns, &rows);
79         cmdlist = columns_sort_list(cmdlist, rows);
80
81         /* rows in last column */
82         last_col_rows = rows-(cols*rows-g_slist_length(cmdlist));
83         if (last_col_rows == 0)
84                 last_col_rows = rows;
85
86         str = g_string_new(NULL);
87         linebuf = g_malloc(max_width+1);
88
89         col = 0; row = 0;
90         for (tmp = cmdlist; tmp != NULL; tmp = tmp->next) {
91                 COMMAND_REC *rec = tmp->data;
92
93                 memset(linebuf, ' ', columns[col]);
94                 linebuf[columns[col]] = '\0';
95                 memcpy(linebuf, rec->cmd, strlen(rec->cmd));
96                 g_string_append(str, linebuf);
97
98                 if (++col == cols) {
99                         printtext(NULL, NULL,
100                                   MSGLEVEL_CLIENTCRAP, "%s", str->str);
101                         g_string_truncate(str, 0);
102                         col = 0; row++;
103
104                         if (row == last_col_rows)
105                                 cols--;
106                 }
107         }
108         if (str->len != 0)
109                 printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "%s", str->str);
110
111         g_slist_free(cmdlist);
112         g_string_free(str, TRUE);
113         g_free(columns);
114         g_free(linebuf);
115 }
116
117 static int show_help_file(const char *file)
118 {
119         const char *helppath;
120         char tmpbuf[1024], *str, *path, **paths, **tmp;
121         LINEBUF_REC *buffer = NULL;
122         int f, ret, recvlen;
123
124         helppath = settings_get_str("help_path");
125
126         paths = g_strsplit(helppath, ":", -1);
127
128         f = -1;
129         for (tmp = paths; *tmp != NULL; tmp++) {
130                 /* helpdir/command or helpdir/category/command */
131                 path = g_strdup_printf("%s/%s", *tmp, file);
132                 f = open(path, O_RDONLY);
133                 g_free(path);
134
135                 if (f != -1)
136                         break;
137
138         }
139
140         g_strfreev(paths);
141
142         if (f == -1)
143                 return FALSE;
144
145         /* just print to screen whatever is in the file */
146         do {
147                 recvlen = read(f, tmpbuf, sizeof(tmpbuf));
148
149                 ret = line_split(tmpbuf, recvlen, &str, &buffer);
150                 if (ret > 0) {
151                         str = g_strconcat("%|", str, NULL);
152                         printtext_string(NULL, NULL, MSGLEVEL_CLIENTCRAP, str);
153                         g_free(str);
154                 }
155         }
156         while (ret > 0);
157         line_split_free(buffer);
158
159         close(f);
160         return TRUE;
161 }
162
163 static void show_help(const char *data)
164 {
165         COMMAND_REC *rec, *last;
166         GSList *tmp, *cmdlist;
167         int items, findlen;
168         int header, found, fullmatch;
169
170         g_return_if_fail(data != NULL);
171
172         /* sort the commands list */
173         commands = g_slist_sort(commands, (GCompareFunc) commands_equal);
174
175         /* print command, sort by category */
176         cmdlist = NULL; last = NULL; header = FALSE; fullmatch = FALSE;
177         items = 0; findlen = strlen(data); found = FALSE;
178         for (tmp = commands; tmp != NULL; last = rec, tmp = tmp->next) {
179                 rec = tmp->data;
180
181                 if (last != NULL && rec->category != NULL &&
182                     (last->category == NULL ||
183                      strcmp(rec->category, last->category) != 0)) {
184                         /* category changed */
185                         if (items > 0) {
186                                 if (!header) {
187                                         printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "Irssi commands:");
188                                         header = TRUE;
189                                 }
190                                 if (last->category != NULL) {
191                                         printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "");
192                                         printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "%s:", last->category);
193                                 }
194                                 help_category(cmdlist, items);
195                         }
196
197                         g_slist_free(cmdlist); cmdlist = NULL;
198                         items = 0;
199                 }
200
201                 if (last != NULL && g_strcasecmp(rec->cmd, last->cmd) == 0)
202                         continue; /* don't display same command twice */
203
204                 if ((int)strlen(rec->cmd) >= findlen &&
205                     g_strncasecmp(rec->cmd, data, findlen) == 0) {
206                         if (rec->cmd[findlen] == '\0') {
207                                 fullmatch = TRUE;
208                                 found = TRUE;
209                                 break;
210                         }
211                         else if (strchr(rec->cmd+findlen+1, ' ') == NULL) {
212                                 /* not a subcommand (and matches the query) */
213                                 items++;
214                                 cmdlist = g_slist_append(cmdlist, rec);
215                                 found = TRUE;
216                         }
217                 }
218         }
219
220         if ((!found || fullmatch) && !show_help_file(data)) {
221                 printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP,
222                           "No help for %s", data);
223         }
224
225         if (*data != '\0' && data[strlen(data)-1] != ' ' &&
226             command_have_sub(data)) {
227                 char *cmd;
228
229                 cmd = g_strconcat(data, " ", NULL);
230                 show_help(cmd);
231                 g_free(cmd);
232         }
233
234         if (items != 0) {
235                 /* display the last category */
236                 if (!header) {
237                         printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP,
238                                   "Irssi commands:");
239                         header = TRUE;
240                 }
241
242                 if (last->category != NULL) {
243                         printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "");
244                         printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP,
245                                   "%s:", last->category);
246                 }
247                 help_category(cmdlist, items);
248                 g_slist_free(cmdlist);
249         }
250 }
251
252 /* SYNTAX: HELP [<command>] */
253 static void cmd_help(const char *data)
254 {
255         char *cmd, *ptr;
256
257         cmd = g_strdup(data);
258         ptr = cmd+strlen(cmd);
259         while (ptr[-1] == ' ') ptr--; *ptr = '\0';
260
261         g_strdown(cmd);
262         show_help(cmd);
263         g_free(cmd);
264 }
265
266 void fe_help_init(void)
267 {
268         settings_add_str("misc", "help_path", HELPDIR);
269         command_bind("help", NULL, (SIGNAL_FUNC) cmd_help);
270 }
271
272 void fe_help_deinit(void)
273 {
274         command_unbind("help", (SIGNAL_FUNC) cmd_help);
275 }