1 /* xgettext sh backend.
2 Copyright (C) 2003 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
39 #define _(s) gettext(s)
41 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
44 /* The sh syntax is defined in POSIX:2001, see
45 http://www.opengroup.org/onlinepubs/007904975/utilities/xcu_chap02.html
47 - Input is broken into words, which are then subject to
48 - tilde expansion ~...
49 - command substitution `...`
50 - variable substitution $var
51 - arithmetic substitution $((...))
52 - field splitting at whitespace (IFS)
53 - wildcard pattern expansion *?
55 - Strings are enclosed in "..."; command substitution, variable
56 substitution and arithmetic substitution are performed here as well.
57 - '...' is a string without substitutions.
58 - The list of resulting words is split into commands by semicolon and
60 - '#' at the beginning of a word introduces a comment until end of line.
61 The parser is implemented in bash-2.05b/parse.y. */
64 /* ====================== Keyword set customization. ====================== */
66 /* If true extract all strings. */
67 static bool extract_all
= false;
69 static hash_table keywords
;
70 static bool default_keywords
= true;
81 x_sh_keyword (const char *name
)
84 default_keywords
= false;
92 if (keywords
.table
== NULL
)
93 init_hash (&keywords
, 100);
95 split_keywordspec (name
, &end
, &argnum1
, &argnum2
);
97 /* The characters between name and end should form a valid C identifier.
98 A colon means an invalid parse in split_keywordspec(). */
99 colon
= strchr (name
, ':');
100 if (colon
== NULL
|| colon
>= end
)
104 insert_entry (&keywords
, name
, end
- name
,
105 (void *) (long) (argnum1
+ (argnum2
<< 10)));
110 /* Finish initializing the keywords hash table.
111 Called after argument processing, before each file is processed. */
115 if (default_keywords
)
117 x_sh_keyword ("gettext");
118 x_sh_keyword ("ngettext:1,2");
119 x_sh_keyword ("eval_gettext");
120 x_sh_keyword ("eval_ngettext:1,2");
121 default_keywords
= false;
126 init_flag_table_sh ()
128 xgettext_record_flag ("gettext:1:pass-sh-format");
129 xgettext_record_flag ("ngettext:1:pass-sh-format");
130 xgettext_record_flag ("ngettext:2:pass-sh-format");
131 xgettext_record_flag ("eval_gettext:1:sh-format");
132 xgettext_record_flag ("eval_ngettext:1:sh-format");
133 xgettext_record_flag ("eval_ngettext:2:sh-format");
137 /* ======================== Reading of characters. ======================== */
139 /* Real filename, used in error messages about the input file. */
140 static const char *real_file_name
;
142 /* Logical filename and line number, used to label the extracted messages. */
143 static char *logical_file_name
;
144 static int line_number
;
146 /* The input file stream. */
150 /* Fetch the next character from the input file. */
159 error (EXIT_FAILURE
, errno
, _("\
160 error while reading \"%s\""), real_file_name
);
168 /* Put back the last fetched character, not EOF. */
178 /* Remove backslash followed by newline from the input stream. */
180 static int phase1_pushback
[1];
181 static int phase1_pushback_length
;
188 if (phase1_pushback_length
)
190 c
= phase1_pushback
[--phase1_pushback_length
];
210 /* Supports only one pushback character. */
212 phase1_ungetc (int c
)
224 if (phase1_pushback_length
== SIZEOF (phase1_pushback
))
226 phase1_pushback
[phase1_pushback_length
++] = c
;
232 /* ========================== Reading of tokens. ========================== */
235 /* A token consists of a sequence of characters. */
238 int allocated
; /* number of allocated 'token_char's */
239 int charcount
; /* number of used 'token_char's */
240 char *chars
; /* the token's constituents */
243 /* Initialize a 'struct token'. */
245 init_token (struct token
*tp
)
248 tp
->chars
= (char *) xmalloc (tp
->allocated
* sizeof (char));
252 /* Free the memory pointed to by a 'struct token'. */
254 free_token (struct token
*tp
)
259 /* Ensure there is enough room in the token for one more character. */
261 grow_token (struct token
*tp
)
263 if (tp
->charcount
== tp
->allocated
)
266 tp
->chars
= (char *) xrealloc (tp
->chars
, tp
->allocated
* sizeof (char));
270 /* Convert a struct token * to a char*. */
272 string_of_token (const struct token
*tp
)
278 str
= (char *) xmalloc (n
+ 1);
279 memcpy (str
, tp
->chars
, n
);
285 /* ========================= Accumulating messages ========================= */
288 static message_list_ty
*mlp
;
291 /* ========================= Accumulating comments ========================= */
295 static size_t bufmax
;
296 static size_t buflen
;
307 if (buflen
>= bufmax
)
309 bufmax
= 2 * bufmax
+ 10;
310 buffer
= xrealloc (buffer
, bufmax
);
312 buffer
[buflen
++] = c
;
319 && (buffer
[buflen
- 1] == ' ' || buffer
[buflen
- 1] == '\t'))
321 if (buflen
>= bufmax
)
323 bufmax
= 2 * bufmax
+ 10;
324 buffer
= xrealloc (buffer
, bufmax
);
326 buffer
[buflen
] = '\0';
327 xgettext_comment_add (buffer
);
331 /* These are for tracking whether comments count as immediately before
333 static int last_comment_line
;
334 static int last_non_comment_line
;
337 /* ========================= Debackslashification ========================== */
339 /* This state tracks the effect of backquotes, double-quotes and single-quotes
340 on the parsing of backslashes. We make a single pass through the input
341 file, keeping the state up to date. This is much faster than accumulating
342 strings and processing them with explicit debackslashification, like the
345 /* The number of nested `...` or "`...`" constructs. Assumed to be <= 32. */
346 static unsigned int nested_backquotes
;
348 /* A bit mask indicating which of the currently open `...` or "`...`"
349 constructs is with double-quotes: "`...`".
350 A bit value of 1 stands for "`...`", a bit value of 0 stands for `...`.
351 Bit position 0 designates the outermost backquotes nesting,
352 bit position 1 the second-outermost backquotes nesting,
354 bit position (nested_backquotes-1) the innermost backquotes nesting. */
355 static unsigned int open_doublequotes_mask
;
357 /* A bit indicating whether a double-quote is currently open inside the
358 innermost backquotes nesting. */
359 static bool open_doublequote
;
361 /* A bit indicating whether a single-quote is currently open inside the
362 innermost backquotes nesting. */
363 static bool open_singlequote
;
366 /* Functions to update the state. */
369 saw_opening_backquote ()
371 if (open_singlequote
)
373 if (open_doublequote
)
374 open_doublequotes_mask
|= (unsigned int) 1 << nested_backquotes
;
376 open_doublequote
= false;
380 saw_closing_backquote ()
383 open_doublequote
= (open_doublequotes_mask
>> nested_backquotes
) & 1;
384 open_doublequotes_mask
&= ((unsigned int) 1 << nested_backquotes
) - 1;
385 open_singlequote
= false; /* just for safety */
389 saw_opening_doublequote ()
391 if (open_singlequote
|| open_doublequote
)
393 open_doublequote
= true;
397 saw_closing_doublequote ()
399 if (open_singlequote
|| !open_doublequote
)
401 open_doublequote
= false;
405 saw_opening_singlequote ()
407 if (open_doublequote
|| open_singlequote
)
409 open_singlequote
= true;
413 saw_closing_singlequote ()
415 if (open_doublequote
|| !open_singlequote
)
417 open_singlequote
= false;
421 /* ========================== Reading of commands ========================== */
423 /* We are only interested in constant strings. Other words need not to be
424 represented precisely. */
427 t_string
, /* constant string */
428 t_other
, /* other string */
429 t_separator
, /* command separator: semicolon or newline */
430 t_redirect
, /* redirection: one of < > >| << <<- >> <> <& >& */
431 t_backquote
, /* closing '`' pseudo word */
432 t_paren
, /* closing ')' pseudo word */
433 t_eof
/* EOF marker */
439 struct token
*token
; /* for t_string */
440 int line_number_at_start
; /* for t_string */
443 /* Free the memory pointed to by a 'struct word'. */
445 free_word (struct word
*wp
)
447 if (wp
->type
== t_string
)
449 free_token (wp
->token
);
454 /* Convert a t_string token to a char*. */
456 string_of_word (const struct word
*wp
)
461 if (!(wp
->type
== t_string
))
463 n
= wp
->token
->charcount
;
464 str
= (char *) xmalloc (n
+ 1);
465 memcpy (str
, wp
->token
->chars
, n
);
471 /* Whitespace recognition. */
474 is_whitespace (int c
)
476 return (c
== ' ' || c
== '\t' || c
== '\n');
479 /* Operator character recognition. */
482 is_operator_start (int c
)
484 return (c
== '|' || c
== '&' || c
== ';' || c
== '<' || c
== '>'
485 || c
== '(' || c
== ')');
489 /* Denotation of a quoted character.
490 The distinction between quoted and unquoted character is important only for
491 the special, whitespace and operator characters; it is irrelevant for
492 alphanumeric characters, '\\' and many others. */
493 #define QUOTED(c) (UCHAR_MAX + 1 + (c))
494 /* Values in the 'unsigned char' range are implicitly unquoted. Among these,
495 the following are important:
496 '"' opening or closing double quote
497 '\'' opening or closing single quote
498 '$' the unknown result of a dollar expansion
499 '`' does not occur - replaced with OPENING_BACKQUOTE or
502 #define OPENING_BACKQUOTE (2 * (UCHAR_MAX + 1) + '`')
503 #define CLOSING_BACKQUOTE (3 * (UCHAR_MAX + 1) + '`')
505 static int phase2_pushback
[2];
506 static int phase2_pushback_length
;
508 /* Return the next character, with backslashes removed.
509 The result is QUOTED(c) for some unsigned char c, if the next character
510 is escaped sufficiently often to make it a regular constituent character,
511 or simply an 'unsigned char' if it has its special meaning (of special,
512 whitespace or operator charcter), or OPENING_BACKQUOTE, CLOSING_BACKQUOTE,
514 It's the caller's responsibility to update the state. */
520 if (phase2_pushback_length
)
522 c
= phase2_pushback
[--phase2_pushback_length
];
532 return (open_doublequote
? QUOTED (c
) : c
);
533 if (!open_singlequote
)
535 if (c
== '"' || c
== '$')
538 return (nested_backquotes
> 0 ? CLOSING_BACKQUOTE
: OPENING_BACKQUOTE
);
542 /* Number of debackslahificication passes that are active at the
544 unsigned int debackslahify
=
545 nested_backquotes
+ (open_singlequote
? 0 : 1);
546 /* Normal number of backslashes that yield a single backslash in the
548 unsigned int expected_count
=
549 (unsigned int) 1 << debackslahify
;
550 /* Number of backslashes found. */
553 for (count
= 1; count
< expected_count
; count
++)
559 if (count
== expected_count
)
562 /* The count of backslashes is > 0 and < expected_count, therefore the
563 result depends on c, the first character after the backslashes.
564 Note: The formulas below don't necessarily have a logic; they were
565 empirically determined such that 1. the xgettext-30 test succeeds,
566 2. the behaviour for count == 0 would correspond to the one without
570 if (!open_singlequote
&& count
> (expected_count
>> 1))
576 return (open_doublequote
? QUOTED (c
) : c
);
580 /* Each debackslahificication pass converts \\ to \ and \" to ";
581 passes corresponding to `...` drop a lone " whereas passes
582 corresponding to "`...`" leave it alone. Therefore, the
583 minimum number of backslashes needed to get one double-quote
584 in the end is open_doublequotes_mask + 1. */
585 if (open_singlequote
)
587 if (count
> open_doublequotes_mask
)
597 if (count
> open_doublequotes_mask
)
600 /* Some of the count values <= open_doublequotes_mask are
601 actually invalid here, but we assume a syntactically
602 correct input file anyway. */
608 /* FIXME: This code looks fishy. */
609 if (count
== expected_count
- 1)
612 /* Some of the count values < expected_count - 1 are
613 actually invalid here, but we assume a syntactically
614 correct input file anyway. */
615 if (nested_backquotes
> 0 && !open_singlequote
616 && count
>= (expected_count
>> 2))
617 return OPENING_BACKQUOTE
;
619 return CLOSING_BACKQUOTE
;
623 if (open_singlequote
)
625 if (count
>= (expected_count
>> 1))
632 /* When not followed by a quoting character or backslash or dollar,
633 a backslash survives a debackslahificication pass unmodified.
634 Therefore each debackslahificication pass performs a
635 count := (count + 1) >> 1
636 operation. Therefore the minimum number of backslashes needed
637 to get one backslash in the end is (expected_count >> 1) + 1. */
638 if (open_doublequote
|| open_singlequote
)
650 if (count
> (expected_count
>> 1))
663 return (open_singlequote
|| open_doublequote
? QUOTED (c
) : c
);
666 /* Supports 2 characters of pushback. */
668 phase2_ungetc (int c
)
680 if (phase2_pushback_length
== SIZEOF (phase2_pushback
))
682 phase2_pushback
[phase2_pushback_length
++] = c
;
688 /* Context lookup table. */
689 static flag_context_list_table_ty
*flag_context_list_table
;
692 /* Forward declaration of local functions. */
693 static enum word_type
read_command_list (int looking_for
,
694 flag_context_ty outer_context
);
698 /* Read the next word.
699 'looking_for' denotes a parse terminator, either CLOSING_BACKQUOTE, ')'
702 read_word (struct word
*wp
, int looking_for
, flag_context_ty context
)
705 bool all_unquoted_digits
;
712 /* Skip a comment up to end of line. */
713 last_comment_line
= line_number
;
718 if (c
== EOF
|| c
== '\n')
720 /* We skip all leading white space, but not EOLs. */
721 if (!(buflen
== 0 && (c
== ' ' || c
== '\t')))
728 /* Comments assumed to be grouped with a message must immediately
729 precede it, with no non-whitespace token on a line between
731 if (last_non_comment_line
> last_comment_line
)
732 xgettext_comment_reset ();
733 wp
->type
= t_separator
;
737 while (is_whitespace (c
));
745 if (c
== '<' || c
== '>')
747 /* Recognize the redirection operators < > >| << <<- >> <> <& >& */
748 int c2
= phase2_getc ();
749 if ((c
== '<' ? c2
== '<' : c2
== '|') || c2
== '>' || c2
== '&')
751 if (c
== '<' && c2
== '<')
753 int c3
= phase2_getc ();
760 wp
->type
= t_redirect
;
764 if (looking_for
== CLOSING_BACKQUOTE
&& c
== CLOSING_BACKQUOTE
)
766 saw_closing_backquote ();
767 wp
->type
= t_backquote
;
768 last_non_comment_line
= line_number
;
772 if (looking_for
== ')' && c
== ')')
775 last_non_comment_line
= line_number
;
779 if (is_operator_start (c
))
781 wp
->type
= (c
== ';' ? t_separator
: t_other
);
786 wp
->token
= (struct token
*) xmalloc (sizeof (struct token
));
787 init_token (wp
->token
);
788 wp
->line_number_at_start
= line_number
;
789 all_unquoted_digits
= true;
791 for (;; c
= phase2_getc ())
796 if (all_unquoted_digits
&& (c
== '<' || c
== '>'))
798 /* Recognize the redirection operators < > >| << <<- >> <> <& >&
799 prefixed with a nonempty sequence of unquoted digits. */
800 int c2
= phase2_getc ();
801 if ((c
== '<' ? c2
== '<' : c2
== '|') || c2
== '>' || c2
== '&')
803 if (c
== '<' && c2
== '<')
805 int c3
= phase2_getc ();
813 wp
->type
= t_redirect
;
814 free_token (wp
->token
);
817 last_non_comment_line
= line_number
;
822 all_unquoted_digits
= all_unquoted_digits
&& (c
>= '0' && c
<= '9');
826 int c2
= phase2_getc ();
829 int c3
= phase2_getc ();
832 /* Arithmetic expression. Skip until the matching closing
834 unsigned int depth
= 2;
849 /* Command substitution. */
851 read_command_list (')', context
);
854 else if (c2
== '\'' && !open_singlequote
)
856 /* Bash builtin for string with ANSI-C escape sequences. */
857 saw_opening_singlequote ();
865 saw_closing_singlequote ();
881 /* Don't call saw_closing_singlequote () here. */
911 if ((c
>= '0' && c
<= '9')
912 || (c
>= 'A' && c
<= 'F')
913 || (c
>= 'a' && c
<= 'f'))
917 if (c
>= '0' && c
<= '9')
919 else if (c
>= 'A' && c
<= 'F')
921 else if (c
>= 'a' && c
<= 'f')
927 if ((c
>= '0' && c
<= '9')
928 || (c
>= 'A' && c
<= 'F')
929 || (c
>= 'a' && c
<= 'f'))
931 if (c
>= '0' && c
<= '9')
932 n
= n
* 16 + c
- '0';
933 else if (c
>= 'A' && c
<= 'F')
934 n
= n
* 16 + 10 + c
- 'A';
935 else if (c
>= 'a' && c
<= 'f')
936 n
= n
* 16 + 10 + c
- 'a';
953 case '0': case '1': case '2': case '3':
954 case '4': case '5': case '6': case '7':
959 if (c
>= '0' && c
<= '7')
964 if (c
>= '0' && c
<= '7')
977 if (wp
->type
== t_string
)
979 grow_token (wp
->token
);
980 wp
->token
->chars
[wp
->token
->charcount
++] =
984 /* The result is a literal string. Don't change wp->type. */
987 else if (c2
== '"' && !open_doublequote
)
989 /* Bash builtin for internationalized string. */
993 saw_opening_doublequote ();
994 pos
.file_name
= logical_file_name
;
995 pos
.line_number
= line_number
;
996 init_token (&string
);
1004 saw_closing_doublequote ();
1007 grow_token (&string
);
1008 string
.chars
[string
.charcount
++] = (unsigned char) c
;
1010 remember_a_message (mlp
, string_of_token (&string
),
1012 free_token (&string
);
1014 error_with_progname
= false;
1015 error (0, 0, _("%s:%lu: warning: the syntax $\"...\" is deprecated due to security reasons; use eval_gettext instead"),
1016 pos
.file_name
, (unsigned long) pos
.line_number
);
1017 error_with_progname
= true;
1019 /* The result at runtime is not constant. Therefore we
1030 if (!open_singlequote
)
1032 /* Handle an opening single quote. */
1033 saw_opening_singlequote ();
1037 /* Handle a closing single quote. */
1038 saw_closing_singlequote ();
1045 if (!open_doublequote
)
1047 /* Handle an opening double quote. */
1048 saw_opening_doublequote ();
1052 /* Handle a closing double quote. */
1053 saw_closing_doublequote ();
1058 if (c
== OPENING_BACKQUOTE
)
1060 /* Handle an opening backquote. */
1061 saw_opening_backquote ();
1063 read_command_list (CLOSING_BACKQUOTE
, context
);
1068 if (c
== CLOSING_BACKQUOTE
)
1071 if (!open_singlequote
&& !open_doublequote
1072 && (is_whitespace (c
) || is_operator_start (c
)))
1075 if (wp
->type
== t_string
)
1077 grow_token (wp
->token
);
1078 wp
->token
->chars
[wp
->token
->charcount
++] = (unsigned char) c
;
1084 if (wp
->type
!= t_string
)
1086 free_token (wp
->token
);
1089 last_non_comment_line
= line_number
;
1093 /* Read the next command.
1094 'looking_for' denotes a parse terminator, either CLOSING_BACKQUOTE, ')'
1096 Returns the type of the word that terminated the command. */
1097 static enum word_type
1098 read_command (int looking_for
, flag_context_ty outer_context
)
1100 /* Read the words that make up the command.
1101 Here we completely ignore field splitting at whitespace and wildcard
1102 expansions; i.e. we assume that the source is written in such a way that
1103 every word in the program determines exactly one word in the resulting
1105 But we do not require that the 'gettext'/'ngettext' command is the
1106 first in the command; this is because 1. we want to allow for prefixes
1107 like "$verbose" that may expand to nothing, and 2. it's a big effort
1108 to know where a command starts in a $(for ...) or $(case ...) compound
1110 int arg
= 0; /* Current argument number. */
1111 bool arg_of_redirect
= false; /* True right after a redirection operator. */
1112 flag_context_list_iterator_ty context_iter
;
1113 int argnum1
= -1; /* First string position. */
1114 int argnum2
= -1; /* Plural string position. */
1115 message_ty
*plural_mp
= NULL
; /* Remember the msgid. */
1120 flag_context_ty inner_context
;
1123 inner_context
= null_context
;
1126 inherited_context (outer_context
,
1127 flag_context_list_iterator_advance (
1130 read_word (&inner
, looking_for
, inner_context
);
1132 /* Recognize end of command. */
1133 if (inner
.type
== t_separator
1134 || inner
.type
== t_backquote
|| inner
.type
== t_paren
1135 || inner
.type
== t_eof
)
1140 if (inner
.type
== t_string
)
1144 pos
.file_name
= logical_file_name
;
1145 pos
.line_number
= inner
.line_number_at_start
;
1146 remember_a_message (mlp
, string_of_word (&inner
),
1147 inner_context
, &pos
);
1151 if (arg_of_redirect
)
1153 /* Ignore arguments of redirection operators. */
1154 arg_of_redirect
= false;
1156 else if (inner
.type
== t_redirect
)
1158 /* Ignore this word and the following one. */
1159 arg_of_redirect
= true;
1163 if (argnum1
< 0 && argnum2
< 0)
1165 /* This is the function position. */
1167 if (inner
.type
== t_string
)
1169 char *function_name
= string_of_word (&inner
);
1170 void *keyword_value
;
1172 if (find_entry (&keywords
,
1173 function_name
, strlen (function_name
),
1177 argnum1
= (int) (long) keyword_value
& ((1 << 10) - 1);
1178 argnum2
= (int) (long) keyword_value
>> 10;
1182 flag_context_list_iterator (
1183 flag_context_list_table_lookup (
1184 flag_context_list_table
,
1185 function_name
, strlen (function_name
)));
1187 free (function_name
);
1190 context_iter
= null_context_list_iterator
;
1194 /* These are the argument positions.
1195 Extract a string if we have reached the right
1196 argument position. */
1199 if (inner
.type
== t_string
)
1204 pos
.file_name
= logical_file_name
;
1205 pos
.line_number
= inner
.line_number_at_start
;
1206 mp
= remember_a_message (mlp
, string_of_word (&inner
),
1207 inner_context
, &pos
);
1212 else if (arg
== argnum2
)
1214 if (inner
.type
== t_string
&& plural_mp
!= NULL
)
1218 pos
.file_name
= logical_file_name
;
1219 pos
.line_number
= inner
.line_number_at_start
;
1220 remember_a_message_plural (plural_mp
, string_of_word (&inner
),
1221 inner_context
, &pos
);
1225 if (arg
>= argnum1
&& arg
>= argnum2
)
1227 /* Stop looking for arguments of the last function_name. */
1228 /* FIXME: What about context_iter? */
1243 /* Read a list of commands.
1244 'looking_for' denotes a parse terminator, either CLOSING_BACKQUOTE, ')'
1246 Returns the type of the word that terminated the command list. */
1247 static enum word_type
1248 read_command_list (int looking_for
, flag_context_ty outer_context
)
1252 enum word_type terminator
;
1254 terminator
= read_command (looking_for
, outer_context
);
1255 if (terminator
!= t_separator
)
1262 extract_sh (FILE *f
,
1263 const char *real_filename
, const char *logical_filename
,
1264 flag_context_list_table_ty
*flag_table
,
1265 msgdomain_list_ty
*mdlp
)
1267 mlp
= mdlp
->item
[0]->messages
;
1270 real_file_name
= real_filename
;
1271 logical_file_name
= xstrdup (logical_filename
);
1274 last_comment_line
= -1;
1275 last_non_comment_line
= -1;
1277 nested_backquotes
= 0;
1278 open_doublequotes_mask
= 0;
1279 open_doublequote
= false;
1280 open_singlequote
= false;
1282 flag_context_list_table
= flag_table
;
1286 /* Eat tokens until eof is seen. */
1287 read_command_list ('\0', null_context
);
1290 real_file_name
= NULL
;
1291 logical_file_name
= NULL
;