2008-02-01 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / helpfile.c
blob34b6bdc4e1149538106a4ca292c0002e9248c38f
1 /* helpfile.c - GnuPG's helpfile feature
2 * Copyright (C) 2007 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG 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 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG 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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <stdlib.h>
24 #include "util.h"
25 #include "i18n.h"
26 #include "membuf.h"
29 /* Try to find KEY in the file FNAME. */
30 static char *
31 findkey_fname (const char *key, const char *fname)
33 gpg_error_t err = 0;
34 FILE *fp;
35 int lnr = 0;
36 int c;
37 char *p, line[256];
38 int in_item = 0;
39 membuf_t mb = MEMBUF_ZERO;
41 fp = fopen (fname, "r");
42 if (!fp)
44 if (errno != ENOENT)
46 err = gpg_error_from_syserror ();
47 log_error (_("can't open `%s': %s\n"), fname, gpg_strerror (err));
49 return NULL;
52 while (fgets (line, DIM(line)-1, fp))
54 lnr++;
56 if (!*line || line[strlen(line)-1] != '\n')
58 /* Eat until end of line. */
59 while ( (c=getc (fp)) != EOF && c != '\n')
61 err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
62 : GPG_ERR_INCOMPLETE_LINE);
63 log_error (_("file `%s', line %d: %s\n"),
64 fname, lnr, gpg_strerror (err));
66 else
67 line[strlen(line)-1] = 0; /* Chop the LF. */
69 again:
70 if (!in_item)
72 /* Allow for empty lines and spaces while not in an item. */
73 for (p=line; spacep (p); p++)
75 if (!*p || *p == '#')
76 continue;
77 if (*line != '.' || spacep(line+1))
79 log_info (_("file `%s', line %d: %s\n"),
80 fname, lnr, _("ignoring garbage line"));
81 continue;
83 trim_trailing_spaces (line);
84 in_item = 1;
85 if (!strcmp (line+1, key))
87 /* Found. Start collecting. */
88 init_membuf (&mb, 1024);
90 continue;
93 /* If in an item only allow for comments in the first column
94 and provide ". " as an escape sequence to allow for
95 leading dots and hash marks in the actual text. */
96 if (*line == '#')
97 continue;
98 if (*line == '.')
100 if (spacep(line+1))
101 p = line + 2;
102 else
104 trim_trailing_spaces (line);
105 in_item = 0;
106 if (is_membuf_ready (&mb))
107 break; /* Yep, found and collected the item. */
108 if (!line[1])
109 continue; /* Just an end of text dot. */
110 goto again; /* A new key line. */
113 else
114 p = line;
116 if (is_membuf_ready (&mb))
118 put_membuf_str (&mb, p);
119 put_membuf (&mb, "\n", 1);
123 if ( !err && ferror (fp) )
125 err = gpg_error_from_syserror ();
126 log_error (_("error reading `%s', line %d: %s\n"),
127 fname, lnr, gpg_strerror (err));
130 fclose (fp);
131 if (is_membuf_ready (&mb))
133 /* We have collected something. */
134 if (err)
136 xfree (get_membuf (&mb, NULL));
137 return NULL;
139 else
141 put_membuf (&mb, "", 1); /* Terminate string. */
142 return get_membuf (&mb, NULL);
145 else
146 return NULL;
150 /* Try the help files depending on the locale. */
151 static char *
152 findkey_locale (const char *key, const char *locname,
153 int only_current_locale, const char *dirname)
155 const char *s;
156 char *fname, *ext, *p;
157 char *result;
159 fname = xtrymalloc (strlen (dirname) + 6 + strlen (locname) + 4 + 1);
160 if (!fname)
161 return NULL;
162 ext = stpcpy (stpcpy (fname, dirname), "/help.");
163 /* Search with locale name and territory. ("help.LL_TT.txt") */
164 if (strchr (locname, '_'))
166 strcpy (stpcpy (ext, locname), ".txt");
167 result = findkey_fname (key, fname);
169 else
170 result = NULL; /* No territory. */
172 if (!result)
174 /* Search with just the locale name - if any. ("help.LL.txt") */
175 if (*locname)
177 for (p=ext, s=locname; *s && *s != '_';)
178 *p++ = *s++;
179 strcpy (p, ".txt");
180 result = findkey_fname (key, fname);
182 else
183 result = NULL;
186 if (!result && (!only_current_locale || !*locname) )
188 /* Last try: Search in file without any locale info. ("help.txt") */
189 strcpy (ext, "txt");
190 result = findkey_fname (key, fname);
193 xfree (fname);
194 return result;
198 /* Return a malloced help text as identified by KEY. The system takes
199 the string from an UTF-8 encoded file to be created by an
200 administrator or as distributed with GnuPG. On a GNU or Unix
201 system the entry is searched in these files:
203 /etc/gnupg/help.LL.txt
204 /etc/gnupg/help.txt
205 /usr/share/gnupg/help.LL.txt
206 /usr/share/gnupg/help.txt
208 Here LL denotes the two digit language code of the current locale.
209 If ONLY_CURRENT_LOCALE is set, the fucntion won;t fallback to the
210 english valiant ("help.txt") unless that locale has been requested.
212 The help file needs to be encoded in UTF-8, lines with a '#' in the
213 first column are comment lines and entirely ignored. Help keys are
214 identified by a key consisting of a single word with a single dot
215 as the first character. All key lines listed without any
216 intervening lines (except for comment lines) lead to the same help
217 text. Lines following the key lines make up the actual hep texts.
221 char *
222 gnupg_get_help_string (const char *key, int only_current_locale)
224 static const char *locname;
225 char *result;
227 if (!locname)
229 char *buffer, *p;
230 int count = 0;
231 const char *s = gnupg_messages_locale_name ();
232 buffer = xtrystrdup (s);
233 if (!buffer)
234 locname = "";
235 else
237 for (p = buffer; *p; p++)
238 if (*p == '.' || *p == '@' || *p == '/' /*(safeguard)*/)
239 *p = 0;
240 else if (*p == '_')
242 if (count++)
243 *p = 0; /* Also cut at a underscore in the territory. */
245 locname = buffer;
249 if (!key || !*key)
250 return NULL;
252 result = findkey_locale (key, locname, only_current_locale,
253 gnupg_sysconfdir ());
254 if (!result)
255 result = findkey_locale (key, locname, only_current_locale,
256 gnupg_datadir ());
258 if (result)
259 trim_trailing_spaces (result);
261 return result;