circumstances. This is such a common typo it seems better to accept
the result of user testing than cling to the original syntax.
Use \fB@\fR to insert a literal \fB@\fR without falling foul of
the expansion syntax.
.SS "Expansion Syntax"
Use \fB@\fR to insert a literal \fB@\fR without falling foul of
the expansion syntax.
.SS "Expansion Syntax"
-Expansions are surrounded by at ("@") symbols take the form of a keyword
-followed by zero or more arguments.
-Arguments may either be quoted by curly brackets ("{" and "}") or separated
+An expansion starts with an at ("@") symbol and takes the form of an expansion
+name followed by zero or more arguments.
+.PP
+Arguments can be quoted by curly brackets ("{" and "}") or separated
by colons (":").
Both kinds may be mixed in a single expansion, though doing so seems
likely to cause confusion.
The descriptions below contain suggested forms for each expansion.
.PP
by colons (":").
Both kinds may be mixed in a single expansion, though doing so seems
likely to cause confusion.
The descriptions below contain suggested forms for each expansion.
.PP
+An expansion is terminated by another "@" symbol, but this is optional in the
+specific case that the last argument is quoted by curly brackets and it is
+followed by whitespace and then some character that is not "{" (since that
+could be interpreted as a further argument).
+.PP
Leading and trailing whitespace in unquoted arguments is ignored, as is
whitespace (including newlines) following a close bracket ("}").
.PP
Leading and trailing whitespace in unquoted arguments is ignored, as is
whitespace (including newlines) following a close bracket ("}").
.PP
++template;
sline = line;
while(*template != '@') {
++template;
sline = line;
while(*template != '@') {
+ /* Skip whitespace */
+ while(isspace((unsigned char)*template))
+ ++template;
dynstr_init(&d);
if(*template == '{') {
/* bracketed arg */
dynstr_init(&d);
if(*template == '{') {
/* bracketed arg */
}
if(!*template) fatal(0, "%s:%d: unterminated expansion", name, sline);
++template;
}
if(!*template) fatal(0, "%s:%d: unterminated expansion", name, sline);
++template;
- /* skip whitespace after closing bracket */
- while(isspace((unsigned char)*template))
- ++template;
+ if(isspace((unsigned char)*template)) {
+ /* We have @{...}<WHITESPACE><SOMETHING> */
+ for(p = template; isspace((unsigned char)*p); ++p)
+ ;
+ /* Now we are looking at <SOMETHING>. If it's "{" then that
+ * must be the next argument. Otherwise we infer that this
+ * is really the end of the expansion. */
+ if(*p != '{')
+ goto finished_expansion;
+ }
} else {
/* unbracketed arg */
} else {
/* unbracketed arg */
- /* leading whitespace is not significant in unquoted args */
- while(isspace((unsigned char)*template))
- ++template;
while(*template
&& *template != '@' && *template != '{' && *template != ':') {
if(*template == '\n') ++line;
while(*template
&& *template != '@' && *template != '{' && *template != ':') {
if(*template == '\n') ++line;
vector_append(&v, d.vec);
}
++template;
vector_append(&v, d.vec);
}
++template;
vector_terminate(&v);
/* @@ terminates this file */
if(v.nvec == 0)
vector_terminate(&v);
/* @@ terminates this file */
if(v.nvec == 0)