1 /* GNU gettext - internationalization aids
2 Copyright (C) 1995-1998, 2000-2010, 2012-2013, 2015-2016, 2019-2020, 2023 Free Software Foundation, Inc.
3
4 This file was written by Peter Miller <millerp@canb.auug.org.au>
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 3 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, see <https://www.gnu.org/licenses/>. */
18
19 #ifndef _MESSAGE_H
20 #define _MESSAGE_H
21
22 #include "str-list.h"
23 #include "pos.h"
24 #include "mem-hash-map.h"
25
26 #include <stdbool.h>
27
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33
34 /* According to Sun's Uniforum proposal the default message domain is
35 named 'messages'. */
36 #define MESSAGE_DOMAIN_DEFAULT "messages"
37
38
39 /* Separator between msgctxt and msgid in .mo files. */
40 #define MSGCTXT_SEPARATOR '\004' /* EOT */
41
42
43 /* Kinds of format strings. */
44 enum format_type
45 {
46 format_c,
47 format_objc,
48 format_cplusplus_brace,
49 format_python,
50 format_python_brace,
51 format_java,
52 format_java_printf,
53 format_csharp,
54 format_javascript,
55 format_scheme,
56 format_lisp,
57 format_elisp,
58 format_librep,
59 format_ruby,
60 format_sh,
61 format_awk,
62 format_lua,
63 format_pascal,
64 format_smalltalk,
65 format_qt,
66 format_qt_plural,
67 format_kde,
68 format_kde_kuit,
69 format_boost,
70 format_tcl,
71 format_perl,
72 format_perl_brace,
73 format_php,
74 format_gcc_internal,
75 format_gfc_internal,
76 format_ycp
77 };
78 #define NFORMATS 31 /* Number of format_type enum values. */
79 extern DLL_VARIABLE const char *const format_language[NFORMATS];
80 extern DLL_VARIABLE const char *const format_language_pretty[NFORMATS];
81
82 /* Is current msgid a format string? */
83 enum is_format
84 {
85 undecided,
86 yes,
87 no,
88 yes_according_to_context,
89 possible,
90 impossible
91 };
92
93 extern bool
94 possible_format_p (enum is_format);
95
96
97 /* Range of an unsigned integer argument. */
98 struct argument_range
99 {
100 int min;
101 int max;
102 };
103
104 /* Tests whether a range is present. */
105 #define has_range_p(range) ((range).min >= 0 && (range).max >= 0)
106
107
108 /* Is current msgid wrappable? */
109 #if 0
110 enum is_wrap
111 {
112 undecided,
113 yes,
114 no
115 };
116 #else /* HACK - C's enum concept is so stupid */
117 #define is_wrap is_format
118 #endif
119
120
121 /* Kinds of syntax checks which apply to strings. */
122 enum syntax_check_type
123 {
124 sc_ellipsis_unicode,
125 sc_space_ellipsis,
126 sc_quote_unicode,
127 sc_bullet_unicode
128 };
129 #define NSYNTAXCHECKS 4
130 extern DLL_VARIABLE const char *const syntax_check_name[NSYNTAXCHECKS];
131
132 /* Is current msgid subject to a syntax check? */
133 #if 0
134 enum is_syntax_check
135 {
136 undecided,
137 yes,
138 no
139 };
140 #else /* HACK - C's enum concept is so stupid */
141 #define is_syntax_check is_format
142 #endif
143
144
145 struct altstr
146 {
147 const char *msgstr;
148 size_t msgstr_len;
149 const char *msgstr_end;
150 string_list_ty *comment;
151 string_list_ty *comment_dot;
152 char *id;
153 };
154
155
156 typedef struct message_ty message_ty;
157 struct message_ty
158 {
159 /* The msgctxt string, if present. */
160 const char *msgctxt;
161
162 /* The msgid string. */
163 const char *msgid;
164
165 /* The msgid's plural, if present. */
166 const char *msgid_plural;
167
168 /* The msgstr strings. */
169 const char *msgstr;
170 /* The number of bytes in msgstr, including the terminating NUL. */
171 size_t msgstr_len;
172
173 /* Position in the source PO file. */
174 lex_pos_ty pos;
175
176 /* Plain comments (#) appearing before the message. */
177 string_list_ty *comment;
178
179 /* Extracted comments (#.) appearing before the message. */
180 string_list_ty *comment_dot;
181
182 /* File position comments (#:) appearing before the message, one for
183 each unique file position instance, sorted by file name and then
184 by line. */
185 size_t filepos_count;
186 lex_pos_ty *filepos;
187
188 /* Informations from special comments (#,).
189 Some of them come from extracted comments. They are manipulated by
190 the tools, e.g. msgmerge. */
191
192 /* Fuzzy means "needs translator review". */
193 bool is_fuzzy;
194
195 /* Designation of format string syntax requirements for specific
196 programming languages. */
197 enum is_format is_format[NFORMATS];
198
199 /* Lower and upper bound for the argument whose format directive can be
200 omitted in specific cases of singular or plural. */
201 struct argument_range range;
202
203 /* Do we want the string to be wrapped in the emitted PO file? */
204 enum is_wrap do_wrap;
205
206 /* Do we want to apply extra syntax checks on the string? */
207 enum is_syntax_check do_syntax_check[NSYNTAXCHECKS];
208
209 /* The prev_msgctxt, prev_msgid and prev_msgid_plural strings appearing
210 before the message, if present. Generated by msgmerge. */
211 const char *prev_msgctxt;
212 const char *prev_msgid;
213 const char *prev_msgid_plural;
214
215 /* If set the message is obsolete and while writing out it should be
216 commented out. */
217 bool obsolete;
218
219 /* Used for checking that messages have been used, in the msgcmp,
220 msgmerge, msgcomm and msgcat programs. */
221 int used;
222
223 /* Used for looking up the target message, in the msgcat program. */
224 message_ty *tmp;
225
226 /* Used for combining alternative translations, in the msgcat program. */
227 int alternative_count;
228 struct altstr *alternative;
229 };
230
231 extern message_ty *
232 message_alloc (const char *msgctxt,
233 const char *msgid, const char *msgid_plural,
234 const char *msgstr, size_t msgstr_len,
235 const lex_pos_ty *pp);
236 #define is_header(mp) ((mp)->msgctxt == NULL && (mp)->msgid[0] == '\0')
237 extern void
238 message_free (message_ty *mp);
239 extern void
240 message_comment_append (message_ty *mp, const char *comment);
241 extern void
242 message_comment_dot_append (message_ty *mp, const char *comment);
243 extern void
244 message_comment_filepos (message_ty *mp, const char *name, size_t line);
245 extern message_ty *
246 message_copy (message_ty *mp);
247
248
249 typedef struct message_list_ty message_list_ty;
250 struct message_list_ty
251 {
252 message_ty **item;
253 size_t nitems;
254 size_t nitems_max;
255 bool use_hashtable;
256 hash_table htable; /* Table mapping msgid to 'message_ty *'. */
257 };
258
259 /* Create a fresh message list.
260 If USE_HASHTABLE is true, a hash table will be used to speed up
261 message_list_search(). USE_HASHTABLE can only be set to true if it is
262 known that the message list will not contain duplicate msgids. */
263 extern message_list_ty *
264 message_list_alloc (bool use_hashtable);
265 /* Free a message list.
266 If keep_messages = 0, also free the messages. If keep_messages = 1, don't
267 free the messages. */
268 extern void
269 message_list_free (message_list_ty *mlp, int keep_messages);
270 extern void
271 message_list_append (message_list_ty *mlp, message_ty *mp);
272 extern void
273 message_list_prepend (message_list_ty *mlp, message_ty *mp);
274 extern void
275 message_list_insert_at (message_list_ty *mlp, size_t n, message_ty *mp);
276 extern void
277 message_list_delete_nth (message_list_ty *mlp, size_t n);
278 typedef bool message_predicate_ty (const message_ty *mp);
279 extern void
280 message_list_remove_if_not (message_list_ty *mlp,
281 message_predicate_ty *predicate);
282 /* Recompute the hash table of a message list after the msgids or msgctxts
283 changed. */
284 extern bool
285 message_list_msgids_changed (message_list_ty *mlp);
286 /* Copy a message list.
287 If copy_level = 0, also copy the messages. If copy_level = 1, share the
288 messages. */
289 extern message_list_ty *
290 message_list_copy (message_list_ty *mlp, int copy_level);
291 extern message_ty *
292 message_list_search (message_list_ty *mlp,
293 const char *msgctxt, const char *msgid);
294 /* Return the message in MLP which maximizes the fuzzy_search_goal_function.
295 Only messages with a fuzzy_search_goal_function > FUZZY_THRESHOLD are
296 considered. In case of several messages with the same goal function value,
297 the one with the smaller index is returned. */
298 extern message_ty *
299 message_list_search_fuzzy (message_list_ty *mlp,
300 const char *msgctxt, const char *msgid);
301
302
303 typedef struct message_list_list_ty message_list_list_ty;
304 struct message_list_list_ty
305 {
306 message_list_ty **item;
307 size_t nitems;
308 size_t nitems_max;
309 };
310
311 extern message_list_list_ty *
312 message_list_list_alloc (void);
313 /* Free a list of message lists.
314 If keep_level = 0, also free the messages. If keep_level = 1, don't free
315 the messages but free the lists. If keep_level = 2, don't free the
316 the messages and the lists. */
317 extern void
318 message_list_list_free (message_list_list_ty *mllp, int keep_level);
319 extern void
320 message_list_list_append (message_list_list_ty *mllp,
321 message_list_ty *mlp);
322 extern void
323 message_list_list_append_list (message_list_list_ty *mllp,
324 message_list_list_ty *mllp2);
325 extern message_ty *
326 message_list_list_search (message_list_list_ty *mllp,
327 const char *msgctxt, const char *msgid);
328 extern message_ty *
329 message_list_list_search_fuzzy (message_list_list_ty *mllp,
330 const char *msgctxt, const char *msgid);
331
332
333 typedef struct msgdomain_ty msgdomain_ty;
334 struct msgdomain_ty
335 {
336 const char *domain;
337 message_list_ty *messages;
338 };
339
340 extern msgdomain_ty *
341 msgdomain_alloc (const char *domain, bool use_hashtable);
342 extern void
343 msgdomain_free (msgdomain_ty *mdp);
344
345
346 typedef struct msgdomain_list_ty msgdomain_list_ty;
347 struct msgdomain_list_ty
348 {
349 msgdomain_ty **item;
350 size_t nitems;
351 size_t nitems_max;
352 bool use_hashtable;
353 const char *encoding; /* canonicalized encoding or NULL if unknown */
354 };
355
356 extern msgdomain_list_ty *
357 msgdomain_list_alloc (bool use_hashtable);
358 extern void
359 msgdomain_list_free (msgdomain_list_ty *mdlp);
360 extern void
361 msgdomain_list_append (msgdomain_list_ty *mdlp, msgdomain_ty *mdp);
362 extern void
363 msgdomain_list_append_list (msgdomain_list_ty *mdlp,
364 msgdomain_list_ty *mdlp2);
365 extern message_list_ty *
366 msgdomain_list_sublist (msgdomain_list_ty *mdlp, const char *domain,
367 bool create);
368 /* Copy a message domain list.
369 If copy_level = 0, also copy the messages. If copy_level = 1, share the
370 messages but copy the domains. If copy_level = 2, share the domains. */
371 extern msgdomain_list_ty *
372 msgdomain_list_copy (msgdomain_list_ty *mdlp, int copy_level);
373 extern message_ty *
374 msgdomain_list_search (msgdomain_list_ty *mdlp,
375 const char *msgctxt, const char *msgid);
376 extern message_ty *
377 msgdomain_list_search_fuzzy (msgdomain_list_ty *mdlp,
378 const char *msgctxt, const char *msgid);
379
380
381 /* The goal function used in fuzzy search.
382 Higher values indicate a closer match.
383 If the result is < LOWER_BOUND, an arbitrary other value < LOWER_BOUND can
384 be returned. */
385 extern double
386 fuzzy_search_goal_function (const message_ty *mp,
387 const char *msgctxt, const char *msgid,
388 double lower_bound);
389
390 /* The threshold for fuzzy-searching.
391 A message is considered only if
392 fuzzy_search_goal_function (mp, given, 0.0) > FUZZY_THRESHOLD. */
393 #define FUZZY_THRESHOLD 0.6
394
395
396 #ifdef __cplusplus
397 }
398 #endif
399
400
401 #endif /* message.h */