fd2dca99af9f4e82f65c9a2b6f3bfad7e0e85f4f
[platform/upstream/libxkbcommon.git] / src / compose / parser.c
1 /*
2  * Copyright © 2013 Ran Benita <ran234@gmail.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23
24 /******************************************************************
25
26               Copyright 1992 by Oki Technosystems Laboratory, Inc.
27               Copyright 1992 by Fuji Xerox Co., Ltd.
28
29 Permission to use, copy, modify, distribute, and sell this software
30 and its documentation for any purpose is hereby granted without fee,
31 provided that the above copyright notice appear in all copies and
32 that both that copyright notice and this permission notice appear
33 in supporting documentation, and that the name of Oki Technosystems
34 Laboratory and Fuji Xerox not be used in advertising or publicity
35 pertaining to distribution of the software without specific, written
36 prior permission.
37 Oki Technosystems Laboratory and Fuji Xerox make no representations
38 about the suitability of this software for any purpose.  It is provided
39 "as is" without express or implied warranty.
40
41 OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES
42 WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
43 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS
44 LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR
45 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
46 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
47 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
48 OR PERFORMANCE OF THIS SOFTWARE.
49
50   Author: Yasuhiro Kawai        Oki Technosystems Laboratory
51   Author: Kazunori Nishihara    Fuji Xerox
52
53 ******************************************************************/
54
55 #include <errno.h>
56
57 #include "utils.h"
58 #include "scanner-utils.h"
59 #include "table.h"
60 #include "paths.h"
61 #include "utf8.h"
62 #include "parser.h"
63
64 #define MAX_LHS_LEN 10
65 #define MAX_INCLUDE_DEPTH 5
66
67 /*
68  * Grammar adapted from libX11/modules/im/ximcp/imLcPrs.c.
69  * See also the XCompose(5) manpage.
70  *
71  * FILE          ::= { [PRODUCTION] [COMMENT] "\n" | INCLUDE }
72  * INCLUDE       ::= "include" '"' INCLUDE_STRING '"'
73  * PRODUCTION    ::= LHS ":" RHS [ COMMENT ]
74  * COMMENT       ::= "#" {<any character except null or newline>}
75  * LHS           ::= EVENT { EVENT }
76  * EVENT         ::= [MODIFIER_LIST] "<" keysym ">"
77  * MODIFIER_LIST ::= (["!"] {MODIFIER} ) | "None"
78  * MODIFIER      ::= ["~"] MODIFIER_NAME
79  * MODIFIER_NAME ::= ("Ctrl"|"Lock"|"Caps"|"Shift"|"Alt"|"Meta")
80  * RHS           ::= ( STRING | keysym | STRING keysym )
81  * STRING        ::= '"' { CHAR } '"'
82  * CHAR          ::= GRAPHIC_CHAR | ESCAPED_CHAR
83  * GRAPHIC_CHAR  ::= locale (codeset) dependent code
84  * ESCAPED_CHAR  ::= ('\\' | '\"' | OCTAL | HEX )
85  * OCTAL         ::= '\' OCTAL_CHAR [OCTAL_CHAR [OCTAL_CHAR]]
86  * OCTAL_CHAR    ::= (0|1|2|3|4|5|6|7)
87  * HEX           ::= '\' (x|X) HEX_CHAR [HEX_CHAR]]
88  * HEX_CHAR      ::= (0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|a|b|c|d|e|f)
89  *
90  * INCLUDE_STRING is a filesystem path, with the following %-expansions:
91  *     %% - '%'.
92  *     %H - The user's home directory (the $HOME environment variable).
93  *     %L - The name of the locale specific Compose file (e.g.,
94  *          "/usr/share/X11/locale/<localename>/Compose").
95  *     %S - The name of the system directory for Compose files (e.g.,
96  *          "/usr/share/X11/locale").
97  */
98
99 enum rules_token {
100     TOK_END_OF_FILE = 0,
101     TOK_END_OF_LINE,
102     TOK_INCLUDE,
103     TOK_INCLUDE_STRING,
104     TOK_LHS_KEYSYM,
105     TOK_COLON,
106     TOK_BANG,
107     TOK_TILDE,
108     TOK_STRING,
109     TOK_IDENT,
110     TOK_ERROR
111 };
112
113 /* Values returned with some tokens, like yylval. */
114 union lvalue {
115     struct {
116         /* Still \0-terminated. */
117         const char *str;
118         size_t len;
119     } string;
120 };
121
122 static enum rules_token
123 lex(struct scanner *s, union lvalue *val)
124 {
125 skip_more_whitespace_and_comments:
126     /* Skip spaces. */
127     while (is_space(peek(s)))
128         if (next(s) == '\n')
129             return TOK_END_OF_LINE;
130
131     /* Skip comments. */
132     if (chr(s, '#')) {
133         skip_to_eol(s);
134         goto skip_more_whitespace_and_comments;
135     }
136
137     /* See if we're done. */
138     if (eof(s)) return TOK_END_OF_FILE;
139
140     /* New token. */
141     s->token_line = s->line;
142     s->token_column = s->column;
143     s->buf_pos = 0;
144
145     /* LHS Keysym. */
146     if (chr(s, '<')) {
147         while (peek(s) != '>' && !eol(s))
148             buf_append(s, next(s));
149         if (!chr(s, '>')) {
150             scanner_err(s, "unterminated keysym literal");
151             return TOK_ERROR;
152         }
153         if (!buf_append(s, '\0')) {
154             scanner_err(s, "keysym literal is too long");
155             return TOK_ERROR;
156         }
157         val->string.str = s->buf;
158         val->string.len = s->buf_pos;
159         return TOK_LHS_KEYSYM;
160     }
161
162     /* Colon. */
163     if (chr(s, ':'))
164         return TOK_COLON;
165     if (chr(s, '!'))
166         return TOK_BANG;
167     if (chr(s, '~'))
168         return TOK_TILDE;
169
170     /* String literal. */
171     if (chr(s, '\"')) {
172         while (!eof(s) && !eol(s) && peek(s) != '\"') {
173             if (chr(s, '\\')) {
174                 uint8_t o;
175                 if (chr(s, '\\')) {
176                     buf_append(s, '\\');
177                 }
178                 else if (chr(s, '"')) {
179                     buf_append(s, '"');
180                 }
181                 else if (chr(s, 'x') || chr(s, 'X')) {
182                     if (hex(s, &o))
183                         buf_append(s, (char) o);
184                     else
185                         scanner_warn(s, "illegal hexadecimal escape sequence in string literal");
186                 }
187                 else if (oct(s, &o)) {
188                     buf_append(s, (char) o);
189                 }
190                 else {
191                     scanner_warn(s, "unknown escape sequence (%c) in string literal", peek(s));
192                     /* Ignore. */
193                 }
194             } else {
195                 buf_append(s, next(s));
196             }
197         }
198         if (!chr(s, '\"')) {
199             scanner_err(s, "unterminated string literal");
200             return TOK_ERROR;
201         }
202         if (!buf_append(s, '\0')) {
203             scanner_err(s, "string literal is too long");
204             return TOK_ERROR;
205         }
206         if (!is_valid_utf8(s->buf, s->buf_pos - 1)) {
207             scanner_err(s, "string literal is not a valid UTF-8 string");
208             return TOK_ERROR;
209         }
210         val->string.str = s->buf;
211         val->string.len = s->buf_pos;
212         return TOK_STRING;
213     }
214
215     /* Identifier or include. */
216     if (is_alpha(peek(s)) || peek(s) == '_') {
217         s->buf_pos = 0;
218         while (is_alnum(peek(s)) || peek(s) == '_')
219             buf_append(s, next(s));
220         if (!buf_append(s, '\0')) {
221             scanner_err(s, "identifier is too long");
222             return TOK_ERROR;
223         }
224
225         if (streq(s->buf, "include"))
226             return TOK_INCLUDE;
227
228         val->string.str = s->buf;
229         val->string.len = s->buf_pos;
230         return TOK_IDENT;
231     }
232
233     /* Discard rest of line. */
234     skip_to_eol(s);
235
236     scanner_err(s, "unrecognized token");
237     return TOK_ERROR;
238 }
239
240 static enum rules_token
241 lex_include_string(struct scanner *s, struct xkb_compose_table *table,
242                    union lvalue *val_out)
243 {
244     while (is_space(peek(s)))
245         if (next(s) == '\n')
246             return TOK_END_OF_LINE;
247
248     s->token_line = s->line;
249     s->token_column = s->column;
250     s->buf_pos = 0;
251
252     if (!chr(s, '\"')) {
253         scanner_err(s, "include statement must be followed by a path");
254         return TOK_ERROR;
255     }
256
257     while (!eof(s) && !eol(s) && peek(s) != '\"') {
258         if (chr(s, '%')) {
259             if (chr(s, '%')) {
260                 buf_append(s, '%');
261             }
262             else if (chr(s, 'H')) {
263                 const char *home = secure_getenv("HOME");
264                 if (!home) {
265                     scanner_err(s, "%%H was used in an include statement, but the HOME environment variable is not set");
266                     return TOK_ERROR;
267                 }
268                 if (!buf_appends(s, home)) {
269                     scanner_err(s, "include path after expanding %%H is too long");
270                     return TOK_ERROR;
271                 }
272             }
273             else if (chr(s, 'L')) {
274                 char *path = get_locale_compose_file_path(table->locale);
275                 if (!path) {
276                     scanner_err(s, "failed to expand %%L to the locale Compose file");
277                     return TOK_ERROR;
278                 }
279                 if (!buf_appends(s, path)) {
280                     free(path);
281                     scanner_err(s, "include path after expanding %%L is too long");
282                     return TOK_ERROR;
283                 }
284                 free(path);
285             }
286             else if (chr(s, 'S')) {
287                 const char *xlocaledir = get_xlocaledir_path();
288                 if (!buf_appends(s, xlocaledir)) {
289                     scanner_err(s, "include path after expanding %%S is too long");
290                     return TOK_ERROR;
291                 }
292             }
293             else {
294                 scanner_err(s, "unknown %% format (%c) in include statement", peek(s));
295                 return TOK_ERROR;
296             }
297         } else {
298             buf_append(s, next(s));
299         }
300     }
301     if (!chr(s, '\"')) {
302         scanner_err(s, "unterminated include statement");
303         return TOK_ERROR;
304     }
305     if (!buf_append(s, '\0')) {
306         scanner_err(s, "include path is too long");
307         return TOK_ERROR;
308     }
309     val_out->string.str = s->buf;
310     val_out->string.len = s->buf_pos;
311     return TOK_INCLUDE_STRING;
312 }
313
314 struct production {
315     xkb_keysym_t lhs[MAX_LHS_LEN];
316     unsigned int len;
317     xkb_keysym_t keysym;
318     char string[256];
319     bool has_keysym;
320     bool has_string;
321
322     /* The matching is as follows: (active_mods & modmask) == mods. */
323     xkb_mod_mask_t modmask;
324     xkb_mod_mask_t mods;
325 };
326
327 static uint32_t
328 add_node(struct xkb_compose_table *table, xkb_keysym_t keysym)
329 {
330     struct compose_node new = {
331         .keysym = keysym,
332         .next = 0,
333         .is_leaf = true,
334     };
335     darray_append(table->nodes, new);
336     return darray_size(table->nodes) - 1;
337 }
338
339 static void
340 add_production(struct xkb_compose_table *table, struct scanner *s,
341                const struct production *production)
342 {
343     unsigned lhs_pos;
344     uint32_t curr;
345     struct compose_node *node;
346
347     curr = 0;
348     node = &darray_item(table->nodes, curr);
349
350     /*
351      * Insert the sequence to the trie, creating new nodes as needed.
352      *
353      * TODO: This can be sped up a bit by first trying the path that the
354      * previous production took, and only then doing the linear search
355      * through the trie levels.  This will work because sequences in the
356      * Compose files are often clustered by a common prefix; especially
357      * in the 1st and 2nd keysyms, which is where the largest variation
358      * (thus, longest search) is.
359      */
360     for (lhs_pos = 0; lhs_pos < production->len; lhs_pos++) {
361         while (production->lhs[lhs_pos] != node->keysym) {
362             if (node->next == 0) {
363                 uint32_t next = add_node(table, production->lhs[lhs_pos]);
364                 /* Refetch since add_node could have realloc()ed. */
365                 node = &darray_item(table->nodes, curr);
366                 node->next = next;
367             }
368
369             curr = node->next;
370             node = &darray_item(table->nodes, curr);
371         }
372
373         if (lhs_pos + 1 == production->len)
374             break;
375
376         if (node->is_leaf) {
377             if (node->u.leaf.utf8 != 0 ||
378                 node->u.leaf.keysym != XKB_KEY_NoSymbol) {
379                 scanner_warn(s, "a sequence already exists which is a prefix of this sequence; overriding");
380                 node->u.leaf.utf8 = 0;
381                 node->u.leaf.keysym = XKB_KEY_NoSymbol;
382             }
383
384             {
385                 uint32_t successor = add_node(table, production->lhs[lhs_pos + 1]);
386                 /* Refetch since add_node could have realloc()ed. */
387                 node = &darray_item(table->nodes, curr);
388                 node->is_leaf = false;
389                 node->u.successor = successor;
390             }
391         }
392
393         curr = node->u.successor;
394         node = &darray_item(table->nodes, curr);
395     }
396
397     if (!node->is_leaf) {
398         scanner_warn(s, "this compose sequence is a prefix of another; skipping line");
399         return;
400     }
401
402     if (node->u.leaf.utf8 != 0 || node->u.leaf.keysym != XKB_KEY_NoSymbol) {
403         if (streq(&darray_item(table->utf8, node->u.leaf.utf8),
404                   production->string) &&
405             node->u.leaf.keysym == production->keysym) {
406             scanner_warn(s, "this compose sequence is a duplicate of another; skipping line");
407             return;
408         }
409         scanner_warn(s, "this compose sequence already exists; overriding");
410     }
411
412     if (production->has_string) {
413         node->u.leaf.utf8 = darray_size(table->utf8);
414         darray_append_items(table->utf8, production->string,
415                             strlen(production->string) + 1);
416     }
417     if (production->has_keysym) {
418         node->u.leaf.keysym = production->keysym;
419     }
420 }
421
422 /* Should match resolve_modifier(). */
423 #define ALL_MODS_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
424
425 static xkb_mod_index_t
426 resolve_modifier(const char *name)
427 {
428     static const struct {
429         const char *name;
430         xkb_mod_index_t mod;
431     } mods[] = {
432         { "Shift", 0 },
433         { "Ctrl", 2 },
434         { "Alt", 3 },
435         { "Meta", 3 },
436         { "Lock", 1 },
437         { "Caps", 1 },
438     };
439
440     for (unsigned i = 0; i < ARRAY_SIZE(mods); i++)
441         if (streq(name, mods[i].name))
442             return mods[i].mod;
443
444     return XKB_MOD_INVALID;
445 }
446
447 static bool
448 parse(struct xkb_compose_table *table, struct scanner *s,
449       unsigned include_depth);
450
451 static bool
452 do_include(struct xkb_compose_table *table, struct scanner *s,
453            const char *path, unsigned include_depth)
454 {
455     FILE *file;
456     bool ok;
457     char *string;
458     size_t size;
459     struct scanner new_s;
460
461     if (include_depth >= MAX_INCLUDE_DEPTH) {
462         scanner_err(s, "maximum include depth (%d) exceeded; maybe there is an include loop?",
463                     MAX_INCLUDE_DEPTH);
464         return false;
465     }
466
467     file = fopen(path, "r");
468     if (!file) {
469         scanner_err(s, "failed to open included Compose file \"%s\": %s",
470                     path, strerror(errno));
471         return false;
472     }
473
474     ok = map_file(file, &string, &size);
475     if (!ok) {
476         scanner_err(s, "failed to read included Compose file \"%s\": %s",
477                     path, strerror(errno));
478         goto err_file;
479     }
480
481     scanner_init(&new_s, table->ctx, string, size, path, s->priv);
482
483     ok = parse(table, &new_s, include_depth + 1);
484     if (!ok)
485         goto err_unmap;
486
487 err_unmap:
488     unmap_file(string, size);
489 err_file:
490     fclose(file);
491     return ok;
492 }
493
494 static bool
495 parse(struct xkb_compose_table *table, struct scanner *s,
496       unsigned include_depth)
497 {
498     enum rules_token tok;
499     union lvalue val;
500     xkb_keysym_t keysym;
501     struct production production;
502     enum { MAX_ERRORS = 10 };
503     int num_errors = 0;
504
505 initial:
506     production.len = 0;
507     production.has_keysym = false;
508     production.has_string = false;
509     production.mods = 0;
510     production.modmask = 0;
511
512     /* fallthrough */
513
514 initial_eol:
515     switch (tok = lex(s, &val)) {
516     case TOK_END_OF_LINE:
517         goto initial_eol;
518     case TOK_END_OF_FILE:
519         goto finished;
520     case TOK_INCLUDE:
521         goto include;
522     default:
523         goto lhs_tok;
524     }
525
526 include:
527     switch (tok = lex_include_string(s, table, &val)) {
528     case TOK_INCLUDE_STRING:
529         goto include_eol;
530     default:
531         goto unexpected;
532     }
533
534 include_eol:
535     switch (tok = lex(s, &val)) {
536     case TOK_END_OF_LINE:
537         if (!do_include(table, s, val.string.str, include_depth))
538             goto fail;
539         goto initial;
540     default:
541         goto unexpected;
542     }
543
544 lhs:
545     tok = lex(s, &val);
546 lhs_tok:
547     switch (tok) {
548     case TOK_COLON:
549         if (production.len <= 0) {
550             scanner_warn(s, "expected at least one keysym on left-hand side; skipping line");
551             goto skip;
552         }
553         goto rhs;
554     case TOK_IDENT:
555         if (streq(val.string.str, "None")) {
556             production.mods = 0;
557             production.modmask = ALL_MODS_MASK;
558             goto lhs_keysym;
559         }
560         goto lhs_mod_list_tok;
561     case TOK_TILDE:
562         goto lhs_mod_list_tok;
563     case TOK_BANG:
564         production.modmask = ALL_MODS_MASK;
565         goto lhs_mod_list;
566     default:
567         goto lhs_keysym_tok;
568     }
569
570 lhs_keysym:
571     tok = lex(s, &val);
572 lhs_keysym_tok:
573     switch (tok) {
574     case TOK_LHS_KEYSYM:
575         keysym = xkb_keysym_from_name(val.string.str, XKB_KEYSYM_NO_FLAGS);
576         if (keysym == XKB_KEY_NoSymbol) {
577             scanner_err(s, "unrecognized keysym \"%s\" on left-hand side",
578                         val.string.str);
579             goto error;
580         }
581         if (production.len + 1 > MAX_LHS_LEN) {
582             scanner_warn(s, "too many keysyms (%d) on left-hand side; skipping line",
583                          MAX_LHS_LEN + 1);
584             goto skip;
585         }
586         production.lhs[production.len++] = keysym;
587         production.mods = 0;
588         production.modmask = 0;
589         goto lhs;
590     default:
591         goto unexpected;
592     }
593
594 lhs_mod_list:
595     tok = lex(s, &val);
596 lhs_mod_list_tok: {
597         bool tilde = false;
598         xkb_mod_index_t mod;
599
600         if (tok != TOK_TILDE && tok != TOK_IDENT)
601             goto lhs_keysym_tok;
602
603         if (tok == TOK_TILDE) {
604             tilde = true;
605             tok = lex(s, &val);
606         }
607
608         if (tok != TOK_IDENT)
609             goto unexpected;
610
611         mod = resolve_modifier(val.string.str);
612         if (mod == XKB_MOD_INVALID) {
613             scanner_err(s, "unrecognized modifier \"%s\"",
614                         val.string.str);
615             goto error;
616         }
617
618         production.modmask |= 1 << mod;
619         if (tilde)
620             production.mods &= ~(1 << mod);
621         else
622             production.mods |= 1 << mod;
623
624         goto lhs_mod_list;
625     }
626
627 rhs:
628     switch (tok = lex(s, &val)) {
629     case TOK_STRING:
630         if (production.has_string) {
631             scanner_warn(s, "right-hand side can have at most one string; skipping line");
632             goto skip;
633         }
634         if (val.string.len <= 0) {
635             scanner_warn(s, "right-hand side string must not be empty; skipping line");
636             goto skip;
637         }
638         if (val.string.len >= sizeof(production.string)) {
639             scanner_warn(s, "right-hand side string is too long; skipping line");
640             goto skip;
641         }
642         strcpy(production.string, val.string.str);
643         production.has_string = true;
644         goto rhs;
645     case TOK_IDENT:
646         keysym = xkb_keysym_from_name(val.string.str, XKB_KEYSYM_NO_FLAGS);
647         if (keysym == XKB_KEY_NoSymbol) {
648             scanner_err(s, "unrecognized keysym \"%s\" on right-hand side",
649                         val.string.str);
650             goto error;
651         }
652         if (production.has_keysym) {
653             scanner_warn(s, "right-hand side can have at most one keysym; skipping line");
654             goto skip;
655         }
656         production.keysym = keysym;
657         production.has_keysym = true;
658     case TOK_END_OF_LINE:
659         if (!production.has_string && !production.has_keysym) {
660             scanner_warn(s, "right-hand side must have at least one of string or keysym; skipping line");
661             goto skip;
662         }
663         add_production(table, s, &production);
664         goto initial;
665     default:
666         goto unexpected;
667     }
668
669 unexpected:
670     if (tok != TOK_ERROR)
671         scanner_err(s, "unexpected token");
672 error:
673     num_errors++;
674     if (num_errors <= MAX_ERRORS)
675         goto skip;
676
677     scanner_err(s, "too many errors");
678     goto fail;
679
680 fail:
681     scanner_err(s, "failed to parse file");
682     return false;
683
684 skip:
685     while (tok != TOK_END_OF_LINE && tok != TOK_END_OF_FILE)
686         tok = lex(s, &val);
687     goto initial;
688
689 finished:
690     return true;
691 }
692
693 bool
694 parse_string(struct xkb_compose_table *table, const char *string, size_t len,
695              const char *file_name)
696 {
697     struct scanner s;
698     scanner_init(&s, table->ctx, string, len, file_name, NULL);
699     if (!parse(table, &s, 0))
700         return false;
701     /* Maybe the allocator can use the excess space. */
702     darray_shrink(table->nodes);
703     darray_shrink(table->utf8);
704     return true;
705 }
706
707 bool
708 parse_file(struct xkb_compose_table *table, FILE *file, const char *file_name)
709 {
710     bool ok;
711     char *string;
712     size_t size;
713
714     ok = map_file(file, &string, &size);
715     if (!ok) {
716         log_err(table->ctx, "Couldn't read Compose file %s: %s\n",
717                 file_name, strerror(errno));
718         return false;
719     }
720
721     ok = parse_string(table, string, size, file_name);
722     unmap_file(string, size);
723     return ok;
724 }