mirror of
https://github.com/mirror/make.git
synced 2025-03-03 14:20:54 +08:00
* function.c (func_file): Support reading from files.
* NEWS: Add information about reading files. * make.texi (File Function): Describe reading files. * tests/scripts/functions/file: Test new features for $(file ...)
This commit is contained in:
parent
fc2ddebdae
commit
2b9dd215d5
4
NEWS
4
NEWS
@ -20,6 +20,10 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=106&set
|
||||
successful or not "0" if not successful. The variable value is unset if no
|
||||
!= or $(shell ...) function has been invoked.
|
||||
|
||||
* The $(file ...) function can now read from a file with $(file <FILE).
|
||||
The function is expanded to the contents of the file. The contents are
|
||||
expanded verbatim except that the final newline, if any, is stripped.
|
||||
|
||||
* VMS-specific changes:
|
||||
|
||||
* Perl test harness now works.
|
||||
|
@ -7521,13 +7521,22 @@ no?), but it is more likely to be a mistake.
|
||||
@findex file
|
||||
@cindex writing to a file
|
||||
@cindex file, writing to
|
||||
@cindex reading from a file
|
||||
@cindex file, reading from
|
||||
|
||||
The @code{file} function allows the makefile to write to a file. Two
|
||||
modes of writing are supported: overwrite, where the text is written
|
||||
to the beginning of the file and any existing content is lost, and
|
||||
append, where the text is written to the end of the file, preserving
|
||||
the existing content. In all cases the file is created if it does not
|
||||
exist.
|
||||
The @code{file} function allows the makefile to write to or read from
|
||||
a file. Two modes of writing are supported: overwrite, where the text
|
||||
is written to the beginning of the file and any existing content is
|
||||
lost, and append, where the text is written to the end of the file,
|
||||
preserving the existing content. In both cases the file is created if
|
||||
it does not exist. It is a fatal error if the file cannot be opened
|
||||
for writing, or if the write operation fails. The @code{file}
|
||||
function expands to the empty string when writing to a file.
|
||||
|
||||
When reading from a file, the @code{file} function expands to the
|
||||
verbatim contents of the file, except that the final newline (if there
|
||||
is one) will be stripped. Attempting to read from a non-existent file
|
||||
expands to the empty string.
|
||||
|
||||
The syntax of the @code{file} function is:
|
||||
|
||||
@ -7535,21 +7544,23 @@ The syntax of the @code{file} function is:
|
||||
$(file @var{op} @var{filename}[,@var{text}])
|
||||
@end example
|
||||
|
||||
The operator @var{op} can be either @code{>} which indicates overwrite
|
||||
mode, or @code{>>} which indicates append mode. The @var{filename}
|
||||
indicates the file to be written to. There may optionally be
|
||||
When the @code{file} function is evaluated all its arguments are
|
||||
expanded first, then the file indicated by @var{filename} will be
|
||||
opened in the mode described by @var{op}.
|
||||
|
||||
The operator @var{op} can be @code{>} to indicate the file will be
|
||||
overwritten with new content, @code{>>} to indicate the current
|
||||
contents of the file will be appended to, or @code{<} to indicate the
|
||||
contents of the file will be read in. The @var{filename} specifies
|
||||
the file to be written to or read from. There may optionally be
|
||||
whitespace between the operator and the file name.
|
||||
|
||||
When the @code{file} function is expanded all its arguments are
|
||||
expanded first, then the file indicated by @var{filename} will be
|
||||
opened in the mode described by @var{op}. Finally @var{text} will be
|
||||
written to the file. If @var{text} does not already end in a newline,
|
||||
even if empty, a final newline will be written. If the @var{text}
|
||||
argument is not given, nothing will be written. The result of
|
||||
evaluating the @code{file} function is always the empty string.
|
||||
When reading files, it is an error to provide a @var{text} value.
|
||||
|
||||
It is a fatal error if the file cannot be opened for writing, or if
|
||||
the write operation fails.
|
||||
When writing files, @var{text} will be written to the file. If
|
||||
@var{text} does not already end in a newline a final newline will be
|
||||
written (even if @var{text} is the empty string). If the @var{text}
|
||||
argument is not given at all, nothing will be written.
|
||||
|
||||
For example, the @code{file} function can be useful if your build
|
||||
system has a limited command line size and your recipe runs a command
|
||||
|
58
function.c
58
function.c
@ -2208,27 +2208,67 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
|
||||
}
|
||||
fn = next_token (fn);
|
||||
|
||||
fp = fopen (fn, mode);
|
||||
if (fn[0] == '\0')
|
||||
O (fatal, *expanding_var, _("file: missing filename"));
|
||||
|
||||
ENULLLOOP (fp, fopen (fn, mode));
|
||||
if (fp == NULL)
|
||||
{
|
||||
const char *err = strerror (errno);
|
||||
OSS (fatal, reading_file, _("open: %s: %s"), fn, err);
|
||||
}
|
||||
OSS (fatal, reading_file, _("open: %s: %s"), fn, strerror (errno));
|
||||
|
||||
if (argv[1])
|
||||
{
|
||||
int l = strlen (argv[1]);
|
||||
int nl = l == 0 || argv[1][l-1] != '\n';
|
||||
|
||||
if (fputs (argv[1], fp) == EOF || (nl && fputc ('\n', fp) == EOF))
|
||||
OSS (fatal, reading_file, _("write: %s: %s"), fn, strerror (errno));
|
||||
}
|
||||
if (fclose (fp))
|
||||
OSS (fatal, reading_file, _("close: %s: %s"), fn, strerror (errno));
|
||||
}
|
||||
else if (fn[0] == '<')
|
||||
{
|
||||
const char *err = strerror (errno);
|
||||
OSS (fatal, reading_file, _("write: %s: %s"), fn, err);
|
||||
char *preo = o;
|
||||
FILE *fp;
|
||||
|
||||
fn = next_token (++fn);
|
||||
if (fn[0] == '\0')
|
||||
O (fatal, *expanding_var, _("file: missing filename"));
|
||||
|
||||
if (argv[1])
|
||||
O (fatal, *expanding_var, _("file: too many arguments"));
|
||||
|
||||
ENULLLOOP (fp, fopen (fn, "r"));
|
||||
if (fp == NULL)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
return o;
|
||||
OSS (fatal, reading_file, _("open: %s: %s"), fn, strerror (errno));
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t l = fread (buf, 1, sizeof (buf), fp);
|
||||
if (l > 0)
|
||||
o = variable_buffer_output (o, buf, l);
|
||||
|
||||
if (ferror (fp))
|
||||
if (errno != EINTR)
|
||||
OSS (fatal, reading_file, _("read: %s: %s"), fn, strerror (errno));
|
||||
if (feof (fp))
|
||||
break;
|
||||
}
|
||||
fclose (fp);
|
||||
if (fclose (fp))
|
||||
OSS (fatal, reading_file, _("close: %s: %s"), fn, strerror (errno));
|
||||
|
||||
/* Remove trailing newline. */
|
||||
if (o > preo && o[-1] == '\n')
|
||||
if (--o > preo && o[-1] == '\r')
|
||||
--o;
|
||||
}
|
||||
else
|
||||
OS (fatal, reading_file, _("Invalid file operation: %s"), fn);
|
||||
OS (fatal, *expanding_var, _("file: invalid file operation: %s"), fn);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
@ -115,4 +115,47 @@ x:;@cat file.out
|
||||
|
||||
unlink('file.out');
|
||||
|
||||
# Reading files
|
||||
run_make_test(q!
|
||||
$(file >file.out,A = foo)
|
||||
X1 := $(file <file.out)
|
||||
$(file >>file.out,B = bar)
|
||||
$(eval $(file <file.out))
|
||||
|
||||
x:;@echo '$(X1)'; echo '$(A)'; echo '$(B)'
|
||||
!,
|
||||
'', "A = foo\nfoo\nbar\n");
|
||||
|
||||
unlink('file.out');
|
||||
|
||||
# Reading from non-existent file
|
||||
run_make_test(q!
|
||||
X1 := $(file <file.out)
|
||||
x:;@echo '$(X1)';
|
||||
!,
|
||||
'', "\n");
|
||||
|
||||
# Extra arguments in read mode
|
||||
run_make_test(q!
|
||||
X1 := $(file <file.out,foo)
|
||||
x:;@echo '$(X1)';
|
||||
!,
|
||||
'', "#MAKEFILE#:2: *** file: too many arguments. Stop.\n", 512);
|
||||
|
||||
|
||||
# Missing filename
|
||||
run_make_test('$(file >)', '',
|
||||
"#MAKEFILE#:1: *** file: missing filename. Stop.\n", 512);
|
||||
|
||||
run_make_test('$(file >>)', '',
|
||||
"#MAKEFILE#:1: *** file: missing filename. Stop.\n", 512);
|
||||
|
||||
run_make_test('$(file <)', '',
|
||||
"#MAKEFILE#:1: *** file: missing filename. Stop.\n", 512);
|
||||
|
||||
# Bad call
|
||||
|
||||
run_make_test('$(file foo)', '',
|
||||
"#MAKEFILE#:1: *** file: invalid file operation: foo. Stop.\n", 512);
|
||||
|
||||
1;
|
||||
|
Loading…
Reference in New Issue
Block a user