mirror of
https://github.com/mirror/make.git
synced 2025-03-03 22:30:59 +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
|
successful or not "0" if not successful. The variable value is unset if no
|
||||||
!= or $(shell ...) function has been invoked.
|
!= 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:
|
* VMS-specific changes:
|
||||||
|
|
||||||
* Perl test harness now works.
|
* Perl test harness now works.
|
||||||
|
@ -7521,13 +7521,22 @@ no?), but it is more likely to be a mistake.
|
|||||||
@findex file
|
@findex file
|
||||||
@cindex writing to a file
|
@cindex writing to a file
|
||||||
@cindex file, writing to
|
@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
|
The @code{file} function allows the makefile to write to or read from
|
||||||
modes of writing are supported: overwrite, where the text is written
|
a file. Two modes of writing are supported: overwrite, where the text
|
||||||
to the beginning of the file and any existing content is lost, and
|
is written to the beginning of the file and any existing content is
|
||||||
append, where the text is written to the end of the file, preserving
|
lost, and append, where the text is written to the end of the file,
|
||||||
the existing content. In all cases the file is created if it does not
|
preserving the existing content. In both cases the file is created if
|
||||||
exist.
|
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:
|
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}])
|
$(file @var{op} @var{filename}[,@var{text}])
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
The operator @var{op} can be either @code{>} which indicates overwrite
|
When the @code{file} function is evaluated all its arguments are
|
||||||
mode, or @code{>>} which indicates append mode. The @var{filename}
|
expanded first, then the file indicated by @var{filename} will be
|
||||||
indicates the file to be written to. There may optionally 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.
|
whitespace between the operator and the file name.
|
||||||
|
|
||||||
When the @code{file} function is expanded all its arguments are
|
When reading files, it is an error to provide a @var{text} value.
|
||||||
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.
|
|
||||||
|
|
||||||
It is a fatal error if the file cannot be opened for writing, or if
|
When writing files, @var{text} will be written to the file. If
|
||||||
the write operation fails.
|
@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
|
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
|
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);
|
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)
|
if (fp == NULL)
|
||||||
{
|
OSS (fatal, reading_file, _("open: %s: %s"), fn, strerror (errno));
|
||||||
const char *err = strerror (errno);
|
|
||||||
OSS (fatal, reading_file, _("open: %s: %s"), fn, err);
|
|
||||||
}
|
|
||||||
if (argv[1])
|
if (argv[1])
|
||||||
{
|
{
|
||||||
int l = strlen (argv[1]);
|
int l = strlen (argv[1]);
|
||||||
int nl = l == 0 || argv[1][l-1] != '\n';
|
int nl = l == 0 || argv[1][l-1] != '\n';
|
||||||
|
|
||||||
if (fputs (argv[1], fp) == EOF || (nl && fputc ('\n', fp) == EOF))
|
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);
|
char *preo = o;
|
||||||
OSS (fatal, reading_file, _("write: %s: %s"), fn, err);
|
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
|
else
|
||||||
OS (fatal, reading_file, _("Invalid file operation: %s"), fn);
|
OS (fatal, *expanding_var, _("file: invalid file operation: %s"), fn);
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
@ -115,4 +115,47 @@ x:;@cat file.out
|
|||||||
|
|
||||||
unlink('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;
|
1;
|
||||||
|
Loading…
Reference in New Issue
Block a user