1 //===- FileCheck.cpp - Check that File's Contents match what is expected --===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // FileCheck does a line-by line check of a file that validates whether it
10 // contains the expected content. This is useful for regression tests etc.
12 // This program exits with an exit status of 2 on error, exit status of 0 if
13 // the file matched the expected contents, and exit status of 1 if it did not
14 // contain the expected contents.
16 //===----------------------------------------------------------------------===//
18 #include "llvm/Support/CommandLine.h"
19 #include "llvm/Support/InitLLVM.h"
20 #include "llvm/Support/Process.h"
21 #include "llvm/Support/WithColor.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include "llvm/Support/FileCheck.h"
27 static cl::opt
<std::string
>
28 CheckFilename(cl::Positional
, cl::desc("<check-file>"), cl::Optional
);
30 static cl::opt
<std::string
>
31 InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
32 cl::init("-"), cl::value_desc("filename"));
34 static cl::list
<std::string
> CheckPrefixes(
36 cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
37 static cl::alias
CheckPrefixesAlias(
38 "check-prefixes", cl::aliasopt(CheckPrefixes
), cl::CommaSeparated
,
41 "Alias for -check-prefix permitting multiple comma separated values"));
43 static cl::opt
<bool> NoCanonicalizeWhiteSpace(
45 cl::desc("Do not treat all horizontal whitespace as equivalent"));
47 static cl::list
<std::string
> ImplicitCheckNot(
49 cl::desc("Add an implicit negative check with this pattern to every\n"
50 "positive check. This can be used to ensure that no instances of\n"
51 "this pattern occur which are not matched by a positive pattern"),
52 cl::value_desc("pattern"));
54 static cl::list
<std::string
>
55 GlobalDefines("D", cl::AlwaysPrefix
,
56 cl::desc("Define a variable to be used in capture patterns."),
57 cl::value_desc("VAR=VALUE"));
59 static cl::opt
<bool> AllowEmptyInput(
60 "allow-empty", cl::init(false),
61 cl::desc("Allow the input file to be empty. This is useful when making\n"
62 "checks that some error message does not occur, for example."));
64 static cl::opt
<bool> MatchFullLines(
65 "match-full-lines", cl::init(false),
66 cl::desc("Require all positive matches to cover an entire input line.\n"
67 "Allows leading and trailing whitespace if --strict-whitespace\n"
68 "is not also passed."));
70 static cl::opt
<bool> EnableVarScope(
71 "enable-var-scope", cl::init(false),
72 cl::desc("Enables scope for regex variables. Variables with names that\n"
73 "do not start with '$' will be reset at the beginning of\n"
74 "each CHECK-LABEL block."));
76 static cl::opt
<bool> AllowDeprecatedDagOverlap(
77 "allow-deprecated-dag-overlap", cl::init(false),
78 cl::desc("Enable overlapping among matches in a group of consecutive\n"
79 "CHECK-DAG directives. This option is deprecated and is only\n"
80 "provided for convenience as old tests are migrated to the new\n"
81 "non-overlapping CHECK-DAG implementation.\n"));
83 static cl::opt
<bool> Verbose(
85 cl::desc("Print directive pattern matches, or add them to the input dump\n"
88 static cl::opt
<bool> VerboseVerbose(
89 "vv", cl::init(false),
90 cl::desc("Print information helpful in diagnosing internal FileCheck\n"
91 "issues, or add it to the input dump if enabled. Implies\n"
93 static const char * DumpInputEnv
= "FILECHECK_DUMP_INPUT_ON_FAILURE";
95 static cl::opt
<bool> DumpInputOnFailure(
96 "dump-input-on-failure", cl::init(std::getenv(DumpInputEnv
)),
97 cl::desc("Dump original input to stderr before failing.\n"
98 "The value can be also controlled using\n"
99 "FILECHECK_DUMP_INPUT_ON_FAILURE environment variable.\n"
100 "This option is deprecated in favor of -dump-input=fail.\n"));
102 enum DumpInputValue
{
110 static cl::opt
<DumpInputValue
> DumpInput(
111 "dump-input", cl::init(DumpInputDefault
),
112 cl::desc("Dump input to stderr, adding annotations representing\n"
113 " currently enabled diagnostics\n"),
114 cl::value_desc("mode"),
115 cl::values(clEnumValN(DumpInputHelp
, "help",
116 "Explain dump format and quit"),
117 clEnumValN(DumpInputNever
, "never", "Never dump input"),
118 clEnumValN(DumpInputFail
, "fail", "Dump input on failure"),
119 clEnumValN(DumpInputAlways
, "always", "Always dump input")));
121 typedef cl::list
<std::string
>::const_iterator prefix_iterator
;
129 static void DumpCommandLine(int argc
, char **argv
) {
130 errs() << "FileCheck command line: ";
131 for (int I
= 0; I
< argc
; I
++)
132 errs() << " " << argv
[I
];
137 /// The starting char (before tildes) for marking the line.
139 /// What color to use for this annotation.
140 raw_ostream::Colors Color
;
141 /// A note to follow the marker, or empty string if none.
144 MarkerStyle(char Lead
, raw_ostream::Colors Color
,
145 const std::string
&Note
= "")
146 : Lead(Lead
), Color(Color
), Note(Note
) {}
149 static MarkerStyle
GetMarker(FileCheckDiag::MatchType MatchTy
) {
151 case FileCheckDiag::MatchFoundAndExpected
:
152 return MarkerStyle('^', raw_ostream::GREEN
);
153 case FileCheckDiag::MatchFoundButExcluded
:
154 return MarkerStyle('!', raw_ostream::RED
, "error: no match expected");
155 case FileCheckDiag::MatchFoundButWrongLine
:
156 return MarkerStyle('!', raw_ostream::RED
, "error: match on wrong line");
157 case FileCheckDiag::MatchFoundButDiscarded
:
158 return MarkerStyle('!', raw_ostream::CYAN
,
159 "discard: overlaps earlier match");
160 case FileCheckDiag::MatchNoneAndExcluded
:
161 return MarkerStyle('X', raw_ostream::GREEN
);
162 case FileCheckDiag::MatchNoneButExpected
:
163 return MarkerStyle('X', raw_ostream::RED
, "error: no match found");
164 case FileCheckDiag::MatchFuzzy
:
165 return MarkerStyle('?', raw_ostream::MAGENTA
, "possible intended match");
167 llvm_unreachable_internal("unexpected match type");
170 static void DumpInputAnnotationHelp(raw_ostream
&OS
) {
171 OS
<< "The following description was requested by -dump-input=help to\n"
172 << "explain the input annotations printed by -dump-input=always and\n"
173 << "-dump-input=fail:\n\n";
175 // Labels for input lines.
177 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "L:";
178 OS
<< " labels line number L of the input file\n";
180 // Labels for annotation lines.
182 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "T:L";
183 OS
<< " labels the only match result for a pattern of type T from "
185 << " the check file\n";
187 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "T:L'N";
188 OS
<< " labels the Nth match result for a pattern of type T from line "
190 << " the check file\n";
192 // Markers on annotation lines.
194 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "^~~";
195 OS
<< " marks good match (reported if -v)\n"
197 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "!~~";
198 OS
<< " marks bad match, such as:\n"
199 << " - CHECK-NEXT on same line as previous match (error)\n"
200 << " - CHECK-NOT found (error)\n"
201 << " - CHECK-DAG overlapping match (discarded, reported if "
204 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "X~~";
205 OS
<< " marks search range when no match is found, such as:\n"
206 << " - CHECK-NEXT not found (error)\n"
207 << " - CHECK-NOT not found (success, reported if -vv)\n"
208 << " - CHECK-DAG not found after discarded matches (error)\n"
210 WithColor(OS
, raw_ostream::SAVEDCOLOR
, true) << "?";
211 OS
<< " marks fuzzy match when no match is found\n";
215 WithColor(OS
, raw_ostream::GREEN
, true) << "success";
217 WithColor(OS
, raw_ostream::RED
, true) << "error";
219 WithColor(OS
, raw_ostream::MAGENTA
, true) << "fuzzy match";
221 WithColor(OS
, raw_ostream::CYAN
, true, false) << "discarded match";
223 WithColor(OS
, raw_ostream::CYAN
, true, true) << "unmatched input";
225 << "If you are not seeing color above or in input dumps, try: -color\n";
228 /// An annotation for a single input line.
229 struct InputAnnotation
{
230 /// The check file line (one-origin indexing) where the directive that
231 /// produced this annotation is located.
233 /// The index of the match result for this check.
234 unsigned CheckDiagIndex
;
235 /// The label for this annotation.
237 /// What input line (one-origin indexing) this annotation marks. This might
238 /// be different from the starting line of the original diagnostic if this is
239 /// a non-initial fragment of a diagnostic that has been broken across
242 /// The column range (one-origin indexing, open end) in which to to mark the
243 /// input line. If InputEndCol is UINT_MAX, treat it as the last column
244 /// before the newline.
245 unsigned InputStartCol
, InputEndCol
;
246 /// The marker to use.
248 /// Whether this annotation represents a good match for an expected pattern.
249 bool FoundAndExpectedMatch
;
252 /// Get an abbreviation for the check type.
253 std::string
GetCheckTypeAbbreviation(Check::FileCheckType Ty
) {
255 case Check::CheckPlain
:
256 if (Ty
.getCount() > 1)
259 case Check::CheckNext
:
261 case Check::CheckSame
:
263 case Check::CheckNot
:
265 case Check::CheckDAG
:
267 case Check::CheckLabel
:
269 case Check::CheckEmpty
:
271 case Check::CheckEOF
:
273 case Check::CheckBadNot
:
275 case Check::CheckBadCount
:
277 case Check::CheckNone
:
278 llvm_unreachable("invalid FileCheckType");
280 llvm_unreachable("unknown FileCheckType");
283 static void BuildInputAnnotations(const std::vector
<FileCheckDiag
> &Diags
,
284 std::vector
<InputAnnotation
> &Annotations
,
285 unsigned &LabelWidth
) {
286 // How many diagnostics has the current check seen so far?
287 unsigned CheckDiagCount
= 0;
288 // What's the widest label?
290 for (auto DiagItr
= Diags
.begin(), DiagEnd
= Diags
.end(); DiagItr
!= DiagEnd
;
294 // Build label, which uniquely identifies this check result.
295 A
.CheckLine
= DiagItr
->CheckLine
;
296 llvm::raw_string_ostream
Label(A
.Label
);
297 Label
<< GetCheckTypeAbbreviation(DiagItr
->CheckTy
) << ":"
298 << DiagItr
->CheckLine
;
299 A
.CheckDiagIndex
= UINT_MAX
;
300 auto DiagNext
= std::next(DiagItr
);
301 if (DiagNext
!= DiagEnd
&& DiagItr
->CheckTy
== DiagNext
->CheckTy
&&
302 DiagItr
->CheckLine
== DiagNext
->CheckLine
)
303 A
.CheckDiagIndex
= CheckDiagCount
++;
304 else if (CheckDiagCount
) {
305 A
.CheckDiagIndex
= CheckDiagCount
;
308 if (A
.CheckDiagIndex
!= UINT_MAX
)
309 Label
<< "'" << A
.CheckDiagIndex
;
311 A
.CheckDiagIndex
= 0;
313 LabelWidth
= std::max((std::string::size_type
)LabelWidth
, A
.Label
.size());
315 MarkerStyle Marker
= GetMarker(DiagItr
->MatchTy
);
317 A
.FoundAndExpectedMatch
=
318 DiagItr
->MatchTy
== FileCheckDiag::MatchFoundAndExpected
;
320 // Compute the mark location, and break annotation into multiple
321 // annotations if it spans multiple lines.
322 A
.InputLine
= DiagItr
->InputStartLine
;
323 A
.InputStartCol
= DiagItr
->InputStartCol
;
324 if (DiagItr
->InputStartLine
== DiagItr
->InputEndLine
) {
325 // Sometimes ranges are empty in order to indicate a specific point, but
326 // that would mean nothing would be marked, so adjust the range to
327 // include the following character.
329 std::max(DiagItr
->InputStartCol
+ 1, DiagItr
->InputEndCol
);
330 Annotations
.push_back(A
);
332 assert(DiagItr
->InputStartLine
< DiagItr
->InputEndLine
&&
333 "expected input range not to be inverted");
334 A
.InputEndCol
= UINT_MAX
;
336 Annotations
.push_back(A
);
337 for (unsigned L
= DiagItr
->InputStartLine
+ 1, E
= DiagItr
->InputEndLine
;
339 // If a range ends before the first column on a line, then it has no
340 // characters on that line, so there's nothing to render.
341 if (DiagItr
->InputEndCol
== 1 && L
== E
) {
342 Annotations
.back().Marker
.Note
= Marker
.Note
;
346 B
.CheckLine
= A
.CheckLine
;
347 B
.CheckDiagIndex
= A
.CheckDiagIndex
;
354 B
.InputEndCol
= UINT_MAX
;
357 B
.InputEndCol
= DiagItr
->InputEndCol
;
358 B
.FoundAndExpectedMatch
= A
.FoundAndExpectedMatch
;
359 Annotations
.push_back(B
);
365 static void DumpAnnotatedInput(raw_ostream
&OS
, const FileCheckRequest
&Req
,
366 StringRef InputFileText
,
367 std::vector
<InputAnnotation
> &Annotations
,
368 unsigned LabelWidth
) {
369 OS
<< "Full input was:\n<<<<<<\n";
373 // First, sort in the order of input lines to make it easier to find relevant
374 // annotations while iterating input lines in the implementation below.
375 // FileCheck diagnostics are not always reported and recorded in the order of
376 // input lines due to, for example, CHECK-DAG and CHECK-NOT.
378 // Second, for annotations for the same input line, sort in the order of the
379 // FileCheck directive's line in the check file (where there's at most one
380 // directive per line) and then by the index of the match result for that
381 // directive. The rationale of this choice is that, for any input line, this
382 // sort establishes a total order of annotations that, with respect to match
383 // results, is consistent across multiple lines, thus making match results
384 // easier to track from one line to the next when they span multiple lines.
385 std::sort(Annotations
.begin(), Annotations
.end(),
386 [](const InputAnnotation
&A
, const InputAnnotation
&B
) {
387 if (A
.InputLine
!= B
.InputLine
)
388 return A
.InputLine
< B
.InputLine
;
389 if (A
.CheckLine
!= B
.CheckLine
)
390 return A
.CheckLine
< B
.CheckLine
;
391 // FIXME: Sometimes CHECK-LABEL reports its match twice with
392 // other diagnostics in between, and then diag index incrementing
393 // fails to work properly, and then this assert fails. We should
394 // suppress one of those diagnostics or do a better job of
395 // computing this index. For now, we just produce a redundant
396 // CHECK-LABEL annotation.
397 // assert(A.CheckDiagIndex != B.CheckDiagIndex &&
398 // "expected diagnostic indices to be unique within a "
400 return A
.CheckDiagIndex
< B
.CheckDiagIndex
;
403 // Compute the width of the label column.
404 const unsigned char *InputFilePtr
= InputFileText
.bytes_begin(),
405 *InputFileEnd
= InputFileText
.bytes_end();
406 unsigned LineCount
= InputFileText
.count('\n');
407 if (InputFileEnd
[-1] != '\n')
409 unsigned LineNoWidth
= std::log10(LineCount
) + 1;
410 // +3 below adds spaces (1) to the left of the (right-aligned) line numbers
411 // on input lines and (2) to the right of the (left-aligned) labels on
412 // annotation lines so that input lines and annotation lines are more
413 // visually distinct. For example, the spaces on the annotation lines ensure
414 // that input line numbers and check directive line numbers never align
415 // horizontally. Those line numbers might not even be for the same file.
416 // One space would be enough to achieve that, but more makes it even easier
418 LabelWidth
= std::max(LabelWidth
, LineNoWidth
) + 3;
420 // Print annotated input lines.
421 auto AnnotationItr
= Annotations
.begin(), AnnotationEnd
= Annotations
.end();
422 for (unsigned Line
= 1;
423 InputFilePtr
!= InputFileEnd
|| AnnotationItr
!= AnnotationEnd
;
425 const unsigned char *InputFileLine
= InputFilePtr
;
427 // Print right-aligned line number.
428 WithColor(OS
, raw_ostream::BLACK
, true)
429 << format_decimal(Line
, LabelWidth
) << ": ";
431 // For the case where -v and colors are enabled, find the annotations for
432 // good matches for expected patterns in order to highlight everything
433 // else in the line. There are no such annotations if -v is disabled.
434 std::vector
<InputAnnotation
> FoundAndExpectedMatches
;
435 if (Req
.Verbose
&& WithColor(OS
).colorsEnabled()) {
436 for (auto I
= AnnotationItr
; I
!= AnnotationEnd
&& I
->InputLine
== Line
;
438 if (I
->FoundAndExpectedMatch
)
439 FoundAndExpectedMatches
.push_back(*I
);
443 // Print numbered line with highlighting where there are no matches for
444 // expected patterns.
445 bool Newline
= false;
448 bool InMatch
= false;
450 COS
.changeColor(raw_ostream::CYAN
, true, true);
451 for (unsigned Col
= 1; InputFilePtr
!= InputFileEnd
&& !Newline
; ++Col
) {
452 bool WasInMatch
= InMatch
;
454 for (auto M
: FoundAndExpectedMatches
) {
455 if (M
.InputStartCol
<= Col
&& Col
< M
.InputEndCol
) {
460 if (!WasInMatch
&& InMatch
)
462 else if (WasInMatch
&& !InMatch
)
463 COS
.changeColor(raw_ostream::CYAN
, true, true);
464 if (*InputFilePtr
== '\n')
467 COS
<< *InputFilePtr
;
472 unsigned InputLineWidth
= InputFilePtr
- InputFileLine
- Newline
;
474 // Print any annotations.
475 while (AnnotationItr
!= AnnotationEnd
&&
476 AnnotationItr
->InputLine
== Line
) {
477 WithColor
COS(OS
, AnnotationItr
->Marker
.Color
, true);
478 // The two spaces below are where the ": " appears on input lines.
479 COS
<< left_justify(AnnotationItr
->Label
, LabelWidth
) << " ";
481 for (Col
= 1; Col
< AnnotationItr
->InputStartCol
; ++Col
)
483 COS
<< AnnotationItr
->Marker
.Lead
;
484 // If InputEndCol=UINT_MAX, stop at InputLineWidth.
485 for (++Col
; Col
< AnnotationItr
->InputEndCol
&& Col
<= InputLineWidth
;
488 const std::string
&Note
= AnnotationItr
->Marker
.Note
;
490 // Put the note at the end of the input line. If we were to instead
491 // put the note right after the marker, subsequent annotations for the
492 // same input line might appear to mark this note instead of the input
494 for (; Col
<= InputLineWidth
; ++Col
)
506 int main(int argc
, char **argv
) {
507 // Enable use of ANSI color codes because FileCheck is using them to
509 llvm::sys::Process::UseANSIEscapeCodes(true);
511 InitLLVM
X(argc
, argv
);
512 cl::ParseCommandLineOptions(argc
, argv
, /*Overview*/ "", /*Errs*/ nullptr,
514 if (DumpInput
== DumpInputHelp
) {
515 DumpInputAnnotationHelp(outs());
518 if (CheckFilename
.empty()) {
519 errs() << "<check-file> not specified\n";
523 FileCheckRequest Req
;
524 for (auto Prefix
: CheckPrefixes
)
525 Req
.CheckPrefixes
.push_back(Prefix
);
527 for (auto CheckNot
: ImplicitCheckNot
)
528 Req
.ImplicitCheckNot
.push_back(CheckNot
);
530 bool GlobalDefineError
= false;
531 for (auto G
: GlobalDefines
) {
532 size_t EqIdx
= G
.find('=');
533 if (EqIdx
== std::string::npos
) {
534 errs() << "Missing equal sign in command-line definition '-D" << G
536 GlobalDefineError
= true;
540 errs() << "Missing variable name in command-line definition '-D" << G
542 GlobalDefineError
= true;
545 Req
.GlobalDefines
.push_back(G
);
547 if (GlobalDefineError
)
550 Req
.AllowEmptyInput
= AllowEmptyInput
;
551 Req
.EnableVarScope
= EnableVarScope
;
552 Req
.AllowDeprecatedDagOverlap
= AllowDeprecatedDagOverlap
;
553 Req
.Verbose
= Verbose
;
554 Req
.VerboseVerbose
= VerboseVerbose
;
555 Req
.NoCanonicalizeWhiteSpace
= NoCanonicalizeWhiteSpace
;
556 Req
.MatchFullLines
= MatchFullLines
;
562 if (!FC
.ValidateCheckPrefixes()) {
563 errs() << "Supplied check-prefix is invalid! Prefixes must be unique and "
564 "start with a letter and contain only alphanumeric characters, "
565 "hyphens and underscores\n";
569 Regex PrefixRE
= FC
.buildCheckPrefixRegex();
571 if (!PrefixRE
.isValid(REError
)) {
572 errs() << "Unable to combine check-prefix strings into a prefix regular "
573 "expression! This is likely a bug in FileCheck's verification of "
574 "the check-prefix strings. Regular expression parsing failed "
575 "with the following error: "
582 // Read the expected strings from the check file.
583 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> CheckFileOrErr
=
584 MemoryBuffer::getFileOrSTDIN(CheckFilename
);
585 if (std::error_code EC
= CheckFileOrErr
.getError()) {
586 errs() << "Could not open check file '" << CheckFilename
587 << "': " << EC
.message() << '\n';
590 MemoryBuffer
&CheckFile
= *CheckFileOrErr
.get();
592 SmallString
<4096> CheckFileBuffer
;
593 StringRef CheckFileText
= FC
.CanonicalizeFile(CheckFile
, CheckFileBuffer
);
595 SM
.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
596 CheckFileText
, CheckFile
.getBufferIdentifier()),
599 std::vector
<FileCheckString
> CheckStrings
;
600 if (FC
.ReadCheckFile(SM
, CheckFileText
, PrefixRE
, CheckStrings
))
603 // Open the file to check and add it to SourceMgr.
604 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> InputFileOrErr
=
605 MemoryBuffer::getFileOrSTDIN(InputFilename
);
606 if (std::error_code EC
= InputFileOrErr
.getError()) {
607 errs() << "Could not open input file '" << InputFilename
608 << "': " << EC
.message() << '\n';
611 MemoryBuffer
&InputFile
= *InputFileOrErr
.get();
613 if (InputFile
.getBufferSize() == 0 && !AllowEmptyInput
) {
614 errs() << "FileCheck error: '" << InputFilename
<< "' is empty.\n";
615 DumpCommandLine(argc
, argv
);
619 SmallString
<4096> InputFileBuffer
;
620 StringRef InputFileText
= FC
.CanonicalizeFile(InputFile
, InputFileBuffer
);
622 SM
.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
623 InputFileText
, InputFile
.getBufferIdentifier()),
626 if (DumpInput
== DumpInputDefault
)
627 DumpInput
= DumpInputOnFailure
? DumpInputFail
: DumpInputNever
;
629 std::vector
<FileCheckDiag
> Diags
;
630 int ExitCode
= FC
.CheckInput(SM
, InputFileText
, CheckStrings
,
631 DumpInput
== DumpInputNever
? nullptr : &Diags
)
634 if (DumpInput
== DumpInputAlways
||
635 (ExitCode
== 1 && DumpInput
== DumpInputFail
)) {
638 << (InputFilename
== "-" ? "<stdin>" : InputFilename
.getValue())
640 << "Check file: " << CheckFilename
<< "\n"
642 << "-dump-input=help describes the format of the following dump.\n"
644 std::vector
<InputAnnotation
> Annotations
;
646 BuildInputAnnotations(Diags
, Annotations
, LabelWidth
);
647 DumpAnnotatedInput(errs(), Req
, InputFileText
, Annotations
, LabelWidth
);