Mercurial > ~mikael > mcabber > hg
annotate mcabber/mcabber/help.c @ 2223:965e0282c128
Backed out changeset fa516ef22145
Turns out that in this hash the value pointer is the same as the
key pointer, so there's no need to free both the key and the value.
author | Mikael Berthe <mikael@lilotux.net> |
---|---|
date | Fri, 06 Nov 2015 22:31:40 +0100 |
parents | 33483d3324cf |
children | f5402d705f67 |
rev | line source |
---|---|
868 | 1 /* |
2 * help.c -- Help command | |
3 * | |
1901
84bb3e893586
Update some file headers
Mikael Berthe <mikael@lilotux.net>
parents:
1821
diff
changeset
|
4 * Copyright (C) 2006-2010 Mikael Berthe <mikael@lilotux.net> |
2019
33483d3324cf
s/Copyrigth/Copyright/ and so on
Myhailo Danylenko <isbear@ukrpost.net>
parents:
1912
diff
changeset
|
5 * Copyright (C) 2009 Myhailo Danylenko <isbear@ukrpost.net> |
868 | 6 * |
7 * This program is free software; you can redistribute it and/or modify | |
8 * it under the terms of the GNU General Public License as published by | |
9 * the Free Software Foundation; either version 2 of the License, or (at | |
10 * your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |
20 * USA | |
21 */ | |
22 | |
1678 | 23 /* |
24 * How it works | |
25 * | |
26 * Main calls help_init, that installs option guards. These guards do | |
27 * nothing, but set help_dirs_stalled flag. When user issues help command, | |
28 * it checks, if help_dirs_stalled flag is set, and if it is, it calls | |
29 * init_help_dirs before performing help search. | |
30 * | |
31 * Options: | |
32 * lang List of semicolon-separated language codes. If unset, will | |
33 * be detected from locale, with fallback to english. | |
34 * help_dirs List of semicolon-seaparated directories, where search for | |
35 * help (in language subdirectories) will be performed. | |
36 * Defaults to DATA_DIR/mcabber/help. | |
37 * help_to_current Print help to current buddy's buffer. | |
38 * | |
39 * XXX: | |
40 * Remove command list from hlp.txt and print detected list of all help | |
41 * topics? | |
42 */ | |
868 | 43 |
1678 | 44 #include <glib.h> |
45 #include <string.h> | |
46 #include <locale.h> | |
47 #include <sys/types.h> | |
48 #include <dirent.h> | |
49 | |
50 #include "logprint.h" | |
51 #include "screen.h" | |
52 #include "hbuf.h" | |
868 | 53 #include "settings.h" |
54 #include "utils.h" | |
55 | |
1678 | 56 static GSList *help_dirs = NULL; |
57 static gboolean help_dirs_stalled = TRUE; | |
868 | 58 |
1678 | 59 void free_help_dirs(void) |
60 { | |
61 GSList *hel; | |
62 | |
63 for (hel = help_dirs; hel; hel = hel->next) | |
64 g_free(hel->data); | |
65 | |
66 g_slist_free(help_dirs); | |
67 | |
68 help_dirs = NULL; | |
69 } | |
70 | |
71 void dir_push_languages(const char *langs, const char *dir) | |
72 { | |
73 const char *lstart = langs; | |
74 const char *lend; | |
75 char *path = expand_filename(dir); | |
76 | |
77 for (lend = strchr(lstart, ';'); lend; lend = strchr(lstart, ';')) { | |
78 char *lang = g_strndup(lstart, lend - lstart); | |
79 char *dir = g_strdup_printf("%s/%s", path, lang); | |
80 | |
81 help_dirs = g_slist_append(help_dirs, dir); | |
82 | |
83 g_free(lang); | |
84 lstart = lend + 1; | |
868 | 85 } |
1678 | 86 |
87 { // finishing element | |
88 char *dir = g_strdup_printf("%s/%s", path, lstart); | |
89 | |
90 help_dirs = g_slist_append(help_dirs, dir); | |
91 } | |
92 | |
93 g_free(path); | |
868 | 94 } |
95 | |
1678 | 96 void init_help_dirs(void) |
868 | 97 { |
1678 | 98 const char *paths; |
99 const char *langs; | |
100 char lang[6]; | |
101 | |
102 if (help_dirs) | |
103 free_help_dirs(); | |
104 | |
105 // initialize variables | |
106 paths = settings_opt_get("help_dirs"); | |
107 if (!paths || !*paths) | |
108 #ifdef DATA_DIR | |
109 paths = DATA_DIR "/mcabber/help"; | |
868 | 110 #else |
1678 | 111 paths = "/usr/local/share/mcabber/help;/usr/share/mcabber/help"; |
112 #endif | |
113 | |
114 langs = settings_opt_get("lang"); | |
115 | |
116 if (!langs || !*langs) { | |
117 char *locale = setlocale(LC_MESSAGES, NULL); | |
868 | 118 |
1678 | 119 // XXX crude method to distinguish between xx_XX xx xx@xxx |
120 // and C POSIX NULL etc. | |
121 if (locale && isalpha(locale[0]) && isalpha(locale[1]) | |
122 && !isalpha(locale[2])) { | |
123 lang[0] = locale[0]; | |
124 lang[1] = locale[1]; | |
125 | |
126 if (lang[0] == 'e' && lang[1] == 'n') | |
127 lang[2] = '\0'; | |
128 else { | |
129 lang[2] = ';'; | |
130 lang[3] = 'e'; | |
131 lang[4] = 'n'; | |
132 lang[5] = '\0'; | |
133 } | |
134 | |
135 langs = lang; | |
136 } else | |
137 langs = "en"; | |
868 | 138 } |
139 | |
1678 | 140 { // parse |
141 const char *pstart = paths; | |
142 const char *pend; | |
1650
cd81806b5947
Try fallback language (en) when help file with current language is not found
Nixtrian
parents:
1599
diff
changeset
|
143 |
1678 | 144 for (pend = strchr(pstart, ';'); pend; pend = strchr(pstart, ';')) { |
145 char *path = g_strndup(pstart, pend - pstart); | |
1650
cd81806b5947
Try fallback language (en) when help file with current language is not found
Nixtrian
parents:
1599
diff
changeset
|
146 |
1678 | 147 dir_push_languages(langs, path); |
1650
cd81806b5947
Try fallback language (en) when help file with current language is not found
Nixtrian
parents:
1599
diff
changeset
|
148 |
1678 | 149 g_free(path); |
150 pstart = pend + 1; | |
151 } | |
868 | 152 |
1678 | 153 // last element |
154 dir_push_languages(langs, pstart); | |
868 | 155 } |
156 | |
1678 | 157 help_dirs_stalled = FALSE; |
158 } | |
159 | |
160 static gboolean do_help_in_dir(const char *arg, const char *path, const char *jid) | |
161 { | |
162 char *fname; | |
163 GIOChannel *channel; | |
164 GString *line; | |
165 int lines = 0; | |
166 | |
167 if (arg && *arg) | |
168 fname = g_strdup_printf("%s/hlp_%s.txt", path, arg); | |
169 else | |
170 fname = g_strdup_printf("%s/hlp.txt", path); | |
1729
e6e89b1d7831
Minor style and header updates
Mikael Berthe <mikael@lilotux.net>
parents:
1678
diff
changeset
|
171 |
1678 | 172 channel = g_io_channel_new_file(fname, "r", NULL); |
173 | |
174 if (!channel) | |
175 return FALSE; | |
176 | |
177 line = g_string_new(NULL); | |
178 | |
179 while (TRUE) { | |
180 gsize endpos; | |
181 GIOStatus ret; | |
1729
e6e89b1d7831
Minor style and header updates
Mikael Berthe <mikael@lilotux.net>
parents:
1678
diff
changeset
|
182 |
1678 | 183 ret = g_io_channel_read_line_string(channel, line, &endpos, NULL); |
184 if (ret != G_IO_STATUS_NORMAL) // XXX G_IO_STATUS_AGAIN? | |
185 break; | |
186 | |
187 line->str[endpos] = '\0'; | |
188 | |
189 if (jid) | |
190 scr_WriteIncomingMessage(jid, line->str, 0, | |
191 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); | |
192 else | |
193 scr_LogPrint(LPRINT_NORMAL, "%s", line->str); | |
194 | |
195 ++lines; | |
868 | 196 } |
1678 | 197 |
1912 | 198 g_io_channel_unref(channel); |
199 | |
1678 | 200 g_string_free(line, TRUE); |
868 | 201 |
1678 | 202 if (!lines) |
203 return FALSE; | |
204 | |
205 if (!jid) { | |
892
94bb9e40e40b
Set the pending message flag on the status buffer when using /help
Mikael Berthe <mikael@lilotux.net>
parents:
882
diff
changeset
|
206 scr_setmsgflag_if_needed(SPECIAL_BUFFER_STATUS_ID, TRUE); |
1815
6abca6000762
Make use of ROSTER_UI_PRIO_STATUS_WIN_MESSAGE
Mikael Berthe <mikael@lilotux.net>
parents:
1729
diff
changeset
|
207 scr_setattentionflag_if_needed(SPECIAL_BUFFER_STATUS_ID, TRUE, |
6abca6000762
Make use of ROSTER_UI_PRIO_STATUS_WIN_MESSAGE
Mikael Berthe <mikael@lilotux.net>
parents:
1729
diff
changeset
|
208 ROSTER_UI_PRIO_STATUS_WIN_MESSAGE, prio_max); |
892
94bb9e40e40b
Set the pending message flag on the status buffer when using /help
Mikael Berthe <mikael@lilotux.net>
parents:
882
diff
changeset
|
209 } |
94bb9e40e40b
Set the pending message flag on the status buffer when using /help
Mikael Berthe <mikael@lilotux.net>
parents:
882
diff
changeset
|
210 |
1678 | 211 return TRUE; |
868 | 212 } |
213 | |
1678 | 214 void help_process(char *arg) |
215 { | |
216 gchar *string; | |
217 const char *jid = NULL; | |
218 gboolean done = FALSE; | |
219 | |
220 if (help_dirs_stalled) | |
221 init_help_dirs(); | |
222 | |
223 { // check input | |
224 char *c; | |
225 | |
226 for (c = arg; *c; ++c) | |
227 if (!isalnum(*c) && *c != '-' && *c != '_') { | |
228 scr_LogPrint(LPRINT_NORMAL, "Wrong help expression, " | |
229 "it can contain only alphbetic, numeric" | |
230 " characters and symbols '-' and '_'."); | |
231 return; | |
232 } | |
233 | |
234 string = g_strdup(arg); | |
235 mc_strtolower(string); | |
236 } | |
237 | |
238 if (settings_opt_get_int("help_to_current") && CURRENT_JID) | |
239 jid = CURRENT_JID; | |
1729
e6e89b1d7831
Minor style and header updates
Mikael Berthe <mikael@lilotux.net>
parents:
1678
diff
changeset
|
240 |
1678 | 241 { // search |
242 GSList *hel; | |
243 | |
244 for (hel = help_dirs; hel && !done; hel = hel->next) { | |
245 char *dir = (char *)hel->data; | |
246 done = do_help_in_dir(string, dir, jid); | |
247 } | |
248 } | |
249 | |
250 if (!done && string && *string) { // match and print any similar topics | |
251 GSList *hel; | |
252 GSList *matches = NULL; | |
253 | |
254 for (hel = help_dirs; hel; hel = hel->next) { | |
255 const char *path = (const char *)hel->data; | |
256 DIR *dd = opendir(path); | |
257 | |
258 if (dd) { | |
259 struct dirent *file; | |
260 | |
261 for (file = readdir(dd); file; file = readdir(dd)) { | |
262 const char *name = file->d_name; | |
263 | |
264 if (name && name[0] == 'h' && name[1] == 'l' && | |
265 name[2] == 'p' && name[3] == '_') { | |
266 const char *nstart = name + 4; | |
267 const char *nend = strrchr(nstart, '.'); | |
268 | |
269 if (nend) { | |
270 gsize len = nend - nstart; | |
271 | |
272 if (g_strstr_len(nstart, len, string)) { | |
273 gchar *match = g_strndup(nstart, len); | |
1729
e6e89b1d7831
Minor style and header updates
Mikael Berthe <mikael@lilotux.net>
parents:
1678
diff
changeset
|
274 |
1678 | 275 if (!g_slist_find_custom(matches, match, |
276 (GCompareFunc)strcmp)) | |
277 matches = g_slist_append(matches, match); | |
278 else | |
279 g_free(match); | |
280 | |
281 done = TRUE; | |
282 } | |
283 } | |
284 } | |
285 } | |
286 | |
287 closedir(dd); | |
288 } | |
289 } | |
290 | |
291 if (done) { | |
292 GString *message = g_string_new("No exact match found. " | |
293 "Keywords, that contain this word:"); | |
294 GSList *wel; | |
295 | |
296 for (wel = matches; wel; wel = wel->next) { | |
297 gchar *word = (gchar *)wel->data; | |
298 | |
299 g_string_append_printf(message, " %s,", word); | |
300 | |
301 g_free(wel->data); | |
302 } | |
303 | |
304 message->str[message->len - 1] = '.'; | |
305 | |
306 g_slist_free(matches); | |
307 | |
308 { | |
309 char *msg = g_string_free(message, FALSE); | |
310 | |
311 if (jid) | |
312 scr_WriteIncomingMessage(jid, msg, 0, | |
313 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); | |
314 else | |
315 scr_LogPrint(LPRINT_NORMAL, "%s", msg); | |
316 | |
317 g_free(msg); | |
318 } | |
319 } | |
320 } | |
321 | |
322 if (!done) { | |
323 if (jid) // XXX | |
324 scr_WriteIncomingMessage(jid, "No help found.", 0, | |
325 HBB_PREFIX_INFO|HBB_PREFIX_NOFLAG, 0); | |
326 else | |
327 scr_LogPrint(LPRINT_NORMAL, "No help found."); | |
328 } | |
329 | |
330 g_free(string); | |
331 } | |
332 | |
333 static gchar *help_guard(const gchar *key, const gchar *new_value) | |
334 { | |
335 help_dirs_stalled = TRUE; | |
336 return g_strdup(new_value); | |
337 } | |
338 | |
339 void help_init(void) | |
340 { | |
341 settings_set_guard("lang", help_guard); | |
342 settings_set_guard("help_dirs", help_guard); | |
343 } | |
344 | |
345 /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2: For Vim users... */ |