summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwlemb <wlemb>2002-06-29 21:44:31 +0000
committerwlemb <wlemb>2002-06-29 21:44:31 +0000
commitb1e38e988e773d47711d8cea364bec4c50bf6a12 (patch)
tree2569353325c78e3399596ab2844d43f52657bab1
parent9d91f66adb9ba252b72646a961f95d3d26af5abe (diff)
downloadgroff-b1e38e988e773d47711d8cea364bec4c50bf6a12.tar.gz
Implementation of string arguments of the form \*[foo arg1 arg2 ...]
* src/roff/troff/input.cc (have_string_arg): New global variable. (read_mode): New enumeration. (read_escape_name): Use it. Update all calls. (read_long_escape_name): Use it. Update all calls. Set have_string_arg if appropriate. (get_char_for_escape_name): Add parameter for handling space character. (interpolate_string_with_args, decode_string_args): New functions. (get_copy, token::next): Call it if necessary. (interpolate_string): Fix error message. * NEWS, doc/groff.texinfo, man/groff.man, man/groff_diff.man: Document it.
-rw-r--r--ChangeLog18
-rw-r--r--NEWS6
-rw-r--r--doc/groff.texinfo43
-rw-r--r--man/groff.man46
-rw-r--r--man/groff_diff.man26
-rw-r--r--src/roff/troff/input.cc130
6 files changed, 205 insertions, 64 deletions
diff --git a/ChangeLog b/ChangeLog
index 1773684d..6ee000c4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2002-06-29 Werner LEMBERG <wl@gnu.org>
+
+ Implementation of string arguments of the form \*[foo arg1 arg2 ...]
+
+ * src/roff/troff/input.cc (have_string_arg): New global variable.
+ (read_mode): New enumeration.
+ (read_escape_name): Use it. Update all calls.
+ (read_long_escape_name): Use it. Update all calls.
+ Set have_string_arg if appropriate.
+ (get_char_for_escape_name): Add parameter for handling space
+ character.
+ (interpolate_string_with_args, decode_string_args): New functions.
+ (get_copy, token::next): Call it if necessary.
+ (interpolate_string): Fix error message.
+
+ * NEWS, doc/groff.texinfo, man/groff.man, man/groff_diff.man:
+ Document it.
+
2002-06-24 Bernd Warken <bwarken@mayn.de>
* man/groff_tmac.man: Updated and extended.
diff --git a/NEWS b/NEWS
index a37c42eb..9b5d343f 100644
--- a/NEWS
+++ b/NEWS
@@ -60,6 +60,12 @@ o Latin-1 character 181 (PS name `mu', Unicode name U+00B5 MICRO SIGN) has
o -Tutf8 is now available on EBCDIC hosts.
+o Strings can take arguments, using this syntax: \*[foo arg1 arg2 ...].
+ Example:
+
+ .ds xxx This is a \\$1 test.
+ \*[xxx nice]
+
o It is now possible to have whitespace between the first and second dot (or
the name of the ending macro) to end a macro definition. Example:
diff --git a/doc/groff.texinfo b/doc/groff.texinfo
index 099b7c86..2f79d13a 100644
--- a/doc/groff.texinfo
+++ b/doc/groff.texinfo
@@ -772,6 +772,8 @@ The section on the @file{man} macro package is partly based on Susan@w{
}G.@: Kleinmann's @file{groff_man} manual page written for the Debian
GNU/Linux system.
+Larry Kollar contributed the section in the @file{ms} macro package.
+
@c =====================================================================
@@ -5370,7 +5372,7 @@ is returned.
The following lists some built-in registers which are not described
elsewhere in this manual. Any register which begins with a @samp{.} is
read-only. A complete listing of all built-in registers can be found in
-@ref{Register Index}.
+appendix@w{ }@ref{Register Index}.
@table @code
@item .F
@@ -8998,21 +9000,28 @@ even this is a read-write string variable).
@DefreqItem {ds1, name [@Var{string}]}
@DefescItem {\\*, , n, }
@DefescItem {\\*, @lparen{}, nm, }
-@DefescListEnd {\\*, @lbrack{}, name, @rbrack{}}
+@DefescListEnd {\\*, @lbrack{}, name arg1 arg2 @dots{}, @rbrack{}}
@cindex string interpolation (@code{\*})
@cindex string expansion (@code{\*})
@cindex interpolation of strings (@code{\*})
@cindex expansion of strings (@code{\*})
+@cindex string arguments
+@cindex arguments, of strings
Define and access a string variable @var{name} (one-character name@w{
}@var{n}, two-character name @var{nm}). If @var{name} already exists,
-@code{ds} overwrites the previous definition.
+@code{ds} overwrites the previous definition. Only the syntax form
+using brackets can take arguments which are handled identically to
+macro arguments; the single exception is that a closing bracket as an
+argument must be enclosed in double quotes. @xref{Request Arguments},
+and @ref{Parameters}.
Example:
@Example
-.ds UX \s-1UNIX\s0\u\s-3tm\s0\d
+.ds foo a \\$1 test
.
-The \*(UX Operating System
+This is \*[foo nice].
+ @result{} This is a nice test.
@endExample
The @code{\*} escape @dfn{interpolates} (expands in-place) a
@@ -9117,8 +9126,7 @@ This is
@result{} This is a funny test.
@endExample
-Diversions and boxes can be also called with string syntax. It is not
-possible to pass arguments to a macro if called with @code{\*}.
+Diversions and boxes can be also called with string syntax.
Another consequence is that you can copy one-line diversions or boxes
to a string.
@@ -9751,9 +9759,9 @@ Exit a macro, immediately returning to the caller.
@cindex @code{\*}, when reading text for a macro
@cindex @code{\\}, when reading text for a macro
@cindex \@key{RET}, when reading text for a macro
-When @code{gtroff} reads in the text for a macro or diversion, it copies
-the text (including request lines, but excluding escapes) into an
-internal buffer. Escapes are converted into an internal form,
+When @code{gtroff} reads in the text for a macro, string, or diversion,
+it copies the text (including request lines, but excluding escapes) into
+an internal buffer. Escapes are converted into an internal form,
except for @code{\n}, @code{\$}, @code{\*}, @code{\\} and
@code{\@key{RET}} which are evaluated and inserted into the text where
the escape was located. This is known as @dfn{copy-in} mode or
@@ -9782,11 +9790,13 @@ The following example prints the numbers 20 and@w{ }10:
@subsection Parameters
@cindex parameters
-The arguments to a macro can be examined using a variety of escapes.
+The arguments to a macro or string can be examined using a variety of
+escapes.
@Defreg {.$}
@cindex number of arguments register (@code{.$})
-The number of arguments in a macro. This is a read-only number register.
+The number of arguments passed to a macro or string. This is a read-only
+number register.
@endDefreg
Any individual argument can be retrieved with one of the following
@@ -9802,9 +9812,9 @@ Retrieve the @var{n}@dmn{th}, @var{nn}@dmn{th} or @var{nnn}@dmn{th}
argument. As usual, the first form only accepts a single number
(larger than zero), the second a two-digit number (larger or equal
to@w{ }10), and the third any positive integer value (larger
-than zero). Macros can have an unlimited number of arguments. Note
-that due to copy-in mode, use two backslashes on these in actual use to
-prevent interpolation until the macro is actually invoked.
+than zero). Macros and strings can have an unlimited number of arguments.
+Note that due to copy-in mode, use two backslashes on these in actual use
+to prevent interpolation until the macro is actually invoked.
@endDefesc
@Defreq {shift, [@Var{n}]}
@@ -9902,7 +9912,8 @@ Here a primitive solution for a two-column macro.
@endExample
@Example
.de 2c-trap
-. ie \\n[right-side] \@{\. nr right-side 0
+. ie \\n[right-side] \@{\
+. nr right-side 0
. po -(\\n[column-length]u + \\n[column-gap]u)
. \" remove trap
. wh -\\n[bottom-margin]u
diff --git a/man/groff.man b/man/groff.man
index 008bab74..1e9128db 100644
--- a/man/groff.man
+++ b/man/groff.man
@@ -2,7 +2,7 @@
.ig
groff.man
-Last update: 25 June 2002
+Last update: 29 June 2002
This file is part of groff, the GNU roff type-setting system.
@@ -83,7 +83,7 @@ FDL in the main directory of the groff source package.
. as @s \f[\*[@f2]]\*[@a]\f[]\"
. shift
. \}
-. \*[@m] \*[@s]\f[R]
+. \*[@m] "\*[@s]\f[R]"
. ft P \" to make \c happy
. rm @m
. rm @s
@@ -521,6 +521,8 @@ request and retrieved by the
.esc *
escape sequences.
.
+Strings can have variables.
+.
.P
.B Register
variables can store numerical values, numbers with a scale unit, and
@@ -564,7 +566,7 @@ The
.I italic
font is called
.B I
-is everywhere available, but on text devices, it is displayed as an
+and is available everywhere, but on text devices it is displayed as an
underlined Roman font.
.
For the graphical output devices, there exist constant-width pendants
@@ -658,7 +660,9 @@ escape sequence.
.
.TP
.character \[dq]
-The double quote is used to enclose arguments in requests and macros.
+The double quote is used to enclose arguments in requests, macros, and
+strings.
+.
In the
.request ds
and
@@ -711,8 +715,8 @@ Otherwise, it is non-special.
\f[CI]space\f[]
Space characters are only functional characters.
.
-They separate the arguments in requests or macros, and the words in
-text lines.
+They separate the arguments in requests, macros, and strings, and the words
+in text lines.
.
They are subject to groff's horizontal spacing calculations.
.
@@ -2351,9 +2355,14 @@ The string stored in the string variable with 1-character name
The string stored in the string variable with 2-character name
.IR st .
.
-.ESC[] * stringvar
+.ESC[] * "stringvar arg1 arg2 .\|.\|."
The string stored in the string variable with arbitrary length name
-.IR stringvar .
+.IR stringvar ,
+taking
+.IR arg1 ,
+.IR arg2 ,
+.I .\|.\|.\&
+as arguments.
.
.\" --------- macro arguments ---------
.
@@ -2365,29 +2374,30 @@ The
request can make a macro have more than one name.
.
.ESC $ x
-Macro argument with 1-place number
+Macro or string argument with 1-place number
.IR x ,
where
.I x
is a digit between 1 and 9.
.
.ESC $( xy
-Macro argument with 2-digit number
+Macro or string argument with 2-digit number
.IR xy .
.
.ESC[] $ nexp
-Macro argument with number
+Macro or string argument with number
.IR nexp ,
where
.I nexp
is a numerical expression evaluating to an integer \[>=]1.
.
.ESC $*
-In a macro, the concatenation of all the arguments separated by spaces.
+In a macro or string, the concatenation of all the arguments separated
+by spaces.
.
.ESC $@
-In a macro, the concatenation of all the arguments with each surrounded
-by double quotes, and separated by spaces.
+In a macro or string, the concatenation of all the arguments with each
+surrounded by double quotes, and separated by spaces.
.
.\" --------- escaped characters ---------
.
@@ -2881,9 +2891,9 @@ escape sequence.
.P
Strings share their name space with macros.
.
-So strings and macros without arguments are roughly equivalent, though
-calling a string like a macro and vice-versa is not stably implemented
-so far.
+So strings and macros without arguments are roughly equivalent; it is
+possible to call a string like a macro and vice-versa, but this often
+leads to unpredictable results.
.
The following strings are predefined in groff.
.
@@ -2942,7 +2952,7 @@ results from request calls.
.PD 0
.
.REG .$
-Number of arguments in the current macro.
+Number of arguments in the current macro or string.
.
.REG .a
Post-line extra line-space most recently utilized using
diff --git a/man/groff_diff.man b/man/groff_diff.man
index 14b32ec4..0c6df2e6 100644
--- a/man/groff_diff.man
+++ b/man/groff_diff.man
@@ -3,7 +3,7 @@
.ig
groff_diff.man
-Last update : 25 June 2002
+Last update : 29 June 2002
This file is part of groff, the GNU roff type-setting system.
It is the source of the man-page groff_diff(7).
@@ -192,9 +192,14 @@ is a new syntax equal to
i.e., to return to the previous font.
.
.TP
-.BI \[rs]*[ xxx ]
+.BI \[rs]*[ "xxx arg1 arg2 .\|.\|." ]
Interpolate string
-.IR xxx .
+.IR xxx ,
+taking
+.IR arg1 ,
+.IR arg2 ,
+.I .\|.\|.\&
+as arguments.
.
.TP
.BI \[rs]n[ xxx ]
@@ -673,24 +678,25 @@ request can make a macro have more than one name.
.
.TP
.B \[rs]$*
-In a macro, the concatenation of all the arguments separated by spaces.
+In a macro or string, the concatenation of all the arguments separated
+by spaces.
.
.TP
.B \[rs]$@
-In a macro, the concatenation of all the arguments with each
+In a macro or string, the concatenation of all the arguments with each
surrounded by double quotes, and separated by spaces.
.
.TP
.BI \[rs]$( nn
.TQ
.BI \[rs]$[ nnn ]
-In a macro, this gives the
+In a macro or string, this gives the
.IR nn -th
or
.IR nnn -th
argument.
.
-Macros can have an unlimited number of arguments.
+Macros and strings can have an unlimited number of arguments.
.
.TP
.BI \[rs]? anything \[rs]?
@@ -2883,8 +2889,8 @@ The same is true for
and
.BR \[rs]Z .
.
-When decoding a macro argument that is delimited by double quotes, a
-character that appears at a different input level to the starting
+When decoding a macro or string argument that is delimited by double
+quotes, a character that appears at a different input level to the starting
delimiter character will not be recognised as the closing delimiter
character.
.
@@ -2986,7 +2992,7 @@ Only the differences are documented here.
The argument to the
.B s
command is in scaled points (units of
-.IR points/ n ,
+.RI points/ n ,
where
.I n
is the argument to the
diff --git a/src/roff/troff/input.cc b/src/roff/troff/input.cc
index 8fd151ee..a4d28682 100644
--- a/src/roff/troff/input.cc
+++ b/src/roff/troff/input.cc
@@ -121,6 +121,8 @@ int have_input = 0; // whether \f, \H, \R, \s, or \S has
int tcommand_flag = 0;
int safer_flag = 1; // safer by default
+int have_string_arg = 0; // whether we have \*[foo bar...]
+
double spread_limit = -3.0 - 1.0; // negative means deactivated
double warn_scale;
@@ -134,9 +136,11 @@ static void copy_mode_error(const char *,
const errarg & = empty_errarg,
const errarg & = empty_errarg);
-static symbol read_escape_name(int no_empty = 1);
-static symbol read_long_escape_name(int no_empty = 1);
+enum read_mode { ALLOW_EMPTY, WITH_ARGS, NO_ARGS };
+static symbol read_escape_name(read_mode mode = NO_ARGS);
+static symbol read_long_escape_name(read_mode mode = NO_ARGS);
static void interpolate_string(symbol);
+static void interpolate_string_with_args(symbol);
static void interpolate_macro(symbol);
static void interpolate_number_format(symbol);
static void interpolate_environment_variable(symbol);
@@ -690,7 +694,7 @@ void shift()
skip_line();
}
-static int get_char_for_escape_name()
+static int get_char_for_escape_name(int allow_space = 0)
{
int c = get_copy(0);
switch (c) {
@@ -704,7 +708,11 @@ static int get_char_for_escape_name()
case '\n':
if (c == '\n')
input_stack::push(make_temp_iterator("\n"));
+ // fall through
case ' ':
+ if (c == ' ' && allow_space)
+ break;
+ // fall through
case '\t':
case '\001':
case '\b':
@@ -729,20 +737,25 @@ static symbol read_two_char_escape_name()
return symbol(buf);
}
-static symbol read_long_escape_name(int no_empty)
+static symbol read_long_escape_name(read_mode mode)
{
int start_level = input_stack::get_level();
char abuf[ABUF_SIZE];
char *buf = abuf;
int buf_size = ABUF_SIZE;
int i = 0;
+ int c;
+ int have_char = 0;
for (;;) {
- int c = get_char_for_escape_name();
+ c = get_char_for_escape_name(have_char && mode == WITH_ARGS);
if (c == 0) {
if (buf != abuf)
a_delete buf;
return NULL_SYMBOL;
}
+ have_char = 1;
+ if (mode == WITH_ARGS && c == ' ')
+ break;
if (i + 2 > buf_size) {
if (buf == abuf) {
buf = new char[ABUF_SIZE*2];
@@ -762,9 +775,11 @@ static symbol read_long_escape_name(int no_empty)
buf[i++] = c;
}
buf[i] = 0;
+ if (c == ' ')
+ have_string_arg = 1;
if (buf == abuf) {
if (i == 0) {
- if (no_empty)
+ if (mode != ALLOW_EMPTY)
copy_mode_error("empty escape name");
return EMPTY_SYMBOL;
}
@@ -777,7 +792,7 @@ static symbol read_long_escape_name(int no_empty)
}
}
-static symbol read_escape_name(int no_empty)
+static symbol read_escape_name(read_mode mode)
{
int c = get_char_for_escape_name();
if (c == 0)
@@ -785,7 +800,7 @@ static symbol read_escape_name(int no_empty)
if (c == '(')
return read_two_char_escape_name();
if (c == '[' && !compatible_flag)
- return read_long_escape_name(no_empty);
+ return read_long_escape_name(mode);
char buf[2];
buf[0] = c;
buf[1] = '\0';
@@ -861,9 +876,15 @@ static int get_copy(node **nd, int defining)
case '*':
{
(void)input_stack::get(0);
- symbol s = read_escape_name();
- if (!(s.is_null() || s.is_empty()))
- interpolate_string(s);
+ symbol s = read_escape_name(WITH_ARGS);
+ if (!(s.is_null() || s.is_empty())) {
+ if (have_string_arg) {
+ have_string_arg = 0;
+ interpolate_string_with_args(s);
+ }
+ else
+ interpolate_string(s);
+ }
break;
}
case 'a':
@@ -1759,9 +1780,15 @@ void token::next()
}
case '*':
{
- symbol nm = read_escape_name();
- if (!(nm.is_null() || nm.is_empty()))
- interpolate_string(nm);
+ symbol nm = read_escape_name(WITH_ARGS);
+ if (!(nm.is_null() || nm.is_empty())) {
+ if (have_string_arg) {
+ have_string_arg = 0;
+ interpolate_string_with_args(nm);
+ }
+ else
+ interpolate_string(nm);
+ }
break;
}
case 'a':
@@ -1804,7 +1831,7 @@ void token::next()
goto handle_escape_char;
case 'f':
{
- symbol s = read_escape_name(0);
+ symbol s = read_escape_name(ALLOW_EMPTY);
if (s.is_null())
break;
const char *p;
@@ -1821,7 +1848,7 @@ void token::next()
}
case 'F':
{
- symbol s = read_escape_name(0);
+ symbol s = read_escape_name(ALLOW_EMPTY);
if (s.is_null())
break;
curenv->set_family(s);
@@ -1879,13 +1906,13 @@ void token::next()
return;
}
case 'm':
- nd = do_glyph_color(read_escape_name(0));
+ nd = do_glyph_color(read_escape_name(ALLOW_EMPTY));
if (!nd)
break;
type = TOKEN_NODE;
return;
case 'M':
- nd = do_fill_color(read_escape_name(0));
+ nd = do_fill_color(read_escape_name(ALLOW_EMPTY));
if (!nd)
break;
type = TOKEN_NODE;
@@ -3382,7 +3409,7 @@ static void decode_args(macro_iterator *mi)
if (!tok.newline() && !tok.eof()) {
node *n;
int c = get_copy(&n);
- for (;;) {
+ for (;;) {
while (c == ' ')
c = get_copy(&n);
if (c == '\n' || c == EOF)
@@ -3424,6 +3451,56 @@ static void decode_args(macro_iterator *mi)
}
}
+static void decode_string_args(macro_iterator *mi)
+{
+ node *n;
+ int c = get_copy(&n);
+ for (;;) {
+ while (c == ' ')
+ c = get_copy(&n);
+ if (c == '\n' || c == EOF) {
+ error("missing `]'");
+ break;
+ }
+ if (c == ']')
+ break;
+ macro arg;
+ int quote_input_level = 0;
+ int done_tab_warning = 0;
+ if (c == '\"') {
+ quote_input_level = input_stack::get_level();
+ c = get_copy(&n);
+ }
+ while (c != EOF && c != '\n'
+ && !(c == ']' && quote_input_level == 0)
+ && !(c == ' ' && quote_input_level == 0)) {
+ if (quote_input_level > 0 && c == '\"'
+ && input_stack::get_level() == quote_input_level) {
+ c = get_copy(&n);
+ if (c == '"') {
+ arg.append(c);
+ c = get_copy(&n);
+ }
+ else
+ break;
+ }
+ else {
+ if (c == 0)
+ arg.append(n);
+ else {
+ if (c == '\t' && quote_input_level == 0 && !done_tab_warning) {
+ warning(WARN_TAB, "tab character in unquoted string argument");
+ done_tab_warning = 1;
+ }
+ arg.append(c);
+ }
+ c = get_copy(&n);
+ }
+ }
+ mi->add_arg(arg);
+ }
+}
+
void macro::invoke(symbol nm)
{
macro_iterator *mi = new macro_iterator(nm, *this);
@@ -3696,13 +3773,26 @@ static void interpolate_string(symbol nm)
request_or_macro *p = lookup_request(nm);
macro *m = p->to_macro();
if (!m)
- error("you can only invoke a string using \\*");
+ error("you can only invoke a string or macro using \\*");
else {
string_iterator *si = new string_iterator(*m, "string", nm);
input_stack::push(si);
}
}
+static void interpolate_string_with_args(symbol s)
+{
+ request_or_macro *p = lookup_request(s);
+ macro *m = p->to_macro();
+ if (!m)
+ error("you can only invoke a string or macro using \\*");
+ else {
+ macro_iterator *mi = new macro_iterator(s, *m);
+ decode_string_args(mi);
+ input_stack::push(mi);
+ }
+}
+
/* This class is used for the implementation of \$@. It is used for
each of the closing double quotes. It artificially increases the
input level by 2, so that the closing double quote will appear to have