'\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-2000 Sun Microsystems, Inc. '\" Copyright (c) 2005 Kevin B. Kenny . All rights reserved '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH expr 3tcl 8.5 Tcl "Tcl Built-In Commands" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME expr \- Evaluate an expression .SH SYNOPSIS \fBexpr \fIarg \fR?\fIarg arg ...\fR? .BE .SH DESCRIPTION .PP The \fIexpr\fR command concatenates \fIarg\fRs, separated by a space, into an expression, and evaluates that expression, returning its value. The operators permitted in an expression include a subset of the operators permitted in C expressions. For those operators common to both Tcl and C, Tcl applies the same meaning and precedence as the corresponding C operators. The value of an expression is often a numeric result, either an integer or a floating-point value, but may also be a non-numeric value. For example, the expression .PP .CS \fBexpr\fR 8.2 + 6 .CE .PP evaluates to 14.2. Expressions differ from C expressions in the way that operands are specified. Expressions also support non-numeric operands, string comparisons, and some additional operators not found in C. .PP When an expression evaluates to an integer, the value is the decimal form of the integer, and when an expression evaluates to a floating-point number, the value is the form produced by the \fB%g\fR format specifier of Tcl's \fBformat\fR command. .PP .VS "TIP 582" You can use \fB#\fR at any point in the expression (except inside double quotes or braces) to start a comment. Comments last to the end of the line or the end of the expression, whichever comes first. .VE "TIP 582" .SS OPERANDS .PP An expression consists of a combination of operands, operators, parentheses and commas, possibly with whitespace between any of these elements, which is ignored. .PP An operand may be specified in any of the following ways: .IP [1] As a numeric value, either integer or floating-point. .IP [2] As a boolean value, using any form understood by \fBstring is\fR \fBboolean\fR. .IP [3] As a variable, using standard \fB$\fR notation. The value of the variable is then the value of the operand. .IP [4] As a string enclosed in double-quotes. Backslash, variable, and command substitution are performed as described in \fBTcl\fR. .IP [5] As a string enclosed in braces. The operand is treated as a braced value as described in \fBTcl\fR. .IP [6] As a Tcl command enclosed in brackets. Command substitution is performed as described in \fBTcl\fR. .IP [7] As a mathematical function such as \fBsin($x)\fR, whose arguments have any of the above forms for operands. See \fBMATH FUNCTIONS\fR below for a discussion of how mathematical functions are handled. .PP Because \fBexpr\fR parses and performs substitutions on values that have already been parsed and substituted by \fBTcl\fR, it is usually best to enclose expressions in braces to avoid the first round of substitutions by \fBTcl\fR. .PP Below are some examples of simple expressions where the value of \fBa\fR is 3 and the value of \fBb\fR is 6. The command on the left side of each line produces the value on the right side. .PP .CS .ta 9c \fBexpr\fR {3.1 + $a} \fI6.1\fR \fBexpr\fR {2 + "$a.$b"} \fI5.6\fR \fBexpr\fR {4*[llength "6 2"]} \fI8\fR \fBexpr\fR {{word one} < "word $a"} \fI0\fR .CE .PP \fBInteger value\fR .PP An integer operand may be specified in decimal (the normal case, the optional first two characters are \fB0d\fR), binary (the first two characters are \fB0b\fR), octal (the first two characters are \fB0o\fR), or hexadecimal (the first two characters are \fB0x\fR) form. For compatibility with older Tcl releases, an operand that begins with \fB0\fR is interpreted as an octal integer even if the second character is not \fBo\fR. .PP \fBFloating-point value\fR .PP A floating-point number may be specified in any of several common decimal formats, and may use the decimal point \fB.\fR, \fBe\fR or \fBE\fR for scientific notation, and the sign characters \fB+\fR and \fB\-\fR. The following are all valid floating-point numbers: 2.1, 3., 6e4, 7.91e+16. The strings \fBInf\fR and \fBNaN\fR, in any combination of case, are also recognized as floating point values. An operand that doesn't have a numeric interpretation must be quoted with either braces or with double quotes. .PP \fBBoolean value\fR .PP A boolean value may be represented by any of the values \fB0\fR, \fBfalse\fR, \fBno\fR, or \fBoff\fR and any of the values \fB1\fR, \fBtrue\fR, \fByes\fR, or \fBon\fR. .PP \fBDigit Separator\fR .PP Digits in any numeric value may be separated with one or more underscore characters, "\fB_\fR", to improve readability. These separators may only appear between digits. The separator may not appear at the start of a numeric value, between the leading 0 and radix specifier, or at the end of a numeric value. Here are some examples: .PP .CS .ta 9c \fBexpr\fR 100_000_000 \fI100000000\fR \fBexpr\fR 0xffff_ffff \fI4294967295\fR \fBformat\fR 0x%x 0b1111_1110_1101_1011 \fI0xfedb\fR .CE .PP .SS OPERATORS .PP For operators having both a numeric mode and a string mode, the numeric mode is chosen when all operands have a numeric interpretation. The integer interpretation of an operand is preferred over the floating-point interpretation. To ensure string operations on arbitrary values it is generally a good idea to use \fBeq\fR, \fBne\fR, or the \fBstring\fR command instead of more versatile operators such as \fB==\fR. .PP Unless otherwise specified, operators accept non-numeric operands. The value of a boolean operation is 1 if true, 0 otherwise. See also \fBstring is\fR \fBboolean\fR. The valid operators, most of which are also available as commands in the \fBtcl::mathop\fR namespace (see \fBmathop\fR(3tcl)), are listed below, grouped in decreasing order of precedence: .TP 20 \fB\-\0\0+\0\0~\0\0!\fR . Unary minus, unary plus, bit-wise NOT, logical NOT. These operators may only be applied to numeric operands, and bit-wise NOT may only be applied to integers. .TP 20 \fB**\fR . Exponentiation. Valid for numeric operands. The maximum exponent value that Tcl can handle if the first number is an integer > 1 is 268435455. .TP 20 \fB*\0\0/\0\0%\fR . Multiply and divide, which are valid for numeric operands, and remainder, which is valid for integers. The remainder, an absolute value smaller than the absolute value of the divisor, has the same sign as the divisor. .RS .PP When applied to integers, division and remainder can be considered to partition the number line into a sequence of adjacent non-overlapping pieces, where each piece is the size of the divisor; the quotient identifies which piece the dividend lies within, and the remainder identifies where within that piece the dividend lies. A consequence of this is that the result of .QW "-57 \fB/\fR 10" is always -6, and the result of .QW "-57 \fB%\fR 10" is always 3. .RE .TP 20 \fB+\0\0\-\fR . Add and subtract. Valid for numeric operands. .TP 20 \fB<<\0\0>>\fR . Left and right shift. Valid for integers. A right shift always propagates the sign bit. .TP 20 \fB<\0\0>\0\0<=\0\0>=\fR . Boolean numeric-preferring comparisons: less than, greater than, less than or equal, and greater than or equal. If either argument is not numeric, the comparison is done using UNICODE string comparison, as with the string comparison operators below, which have the same precedence. .TP 20 \fBlt\0\0gt\0\0le\0\0ge\fR .VS "8.7, TIP461" Boolean string comparisons: less than, greater than, less than or equal, and greater than or equal. These always compare values using their UNICODE strings (also see \fBstring compare\fR), unlike with the numeric-preferring comparisons abov, which have the same precedence. .VE "8.7, TIP461" .TP 20 \fB==\0\0!=\fR . Boolean equal and not equal. .TP 20 \fBeq\0\0ne\fR . Boolean string equal and string not equal. .TP 20 \fBin\0\0ni\fR . List containment and negated list containment. The first argument is interpreted as a string, the second as a list. \fBin\fR tests for membership in the list, and \fBni\fR is the inverse. .TP 20 \fB&\fR . Bit-wise AND. Valid for integer operands. .TP 20 \fB^\fR . Bit-wise exclusive OR. Valid for integer operands. .TP 20 \fB|\fR . Bit-wise OR. Valid for integer operands. .TP 20 \fB&&\fR . Logical AND. If both operands are true, the result is 1, or 0 otherwise. This operator evaluates lazily; it only evaluates its second operand if it must in order to determine its result. This operator evaluates lazily; it only evaluates its second operand if it must in order to determine its result. .TP 20 \fB||\fR . Logical OR. If both operands are false, the result is 0, or 1 otherwise. This operator evaluates lazily; it only evaluates its second operand if it must in order to determine its result. .TP 20 \fIx \fB?\fI y \fB:\fI z\fR . If-then-else, as in C. If \fIx\fR is false , the result is the value of \fIy\fR. Otherwise the result is the value of \fIz\fR. This operator evaluates lazily; it evaluates only one of \fIy\fR or \fIz\fR. .PP The exponentiation operator promotes types in the same way that the multiply and divide operators do, and the result is is the same as the result of \fBpow\fR. Exponentiation groups right-to-left within a precedence level. Other binary operators group left-to-right. For example, the value of .PP .PP .CS \fBexpr\fR {4*2 < 7} .CE .PP is 0, while the value of .PP .CS \fBexpr\fR {2**3**2} .CE .PP is 512. .PP As in C, \fB&&\fR, \fB||\fR, and \fB?:\fR feature .QW "lazy evaluation" , which means that operands are not evaluated if they are not needed to determine the outcome. For example, in .PP .CS \fBexpr\fR {$v?[a]:[b]} .CE .PP only one of \fB[a]\fR or \fB[b]\fR is evaluated, depending on the value of \fB$v\fR. This is not true of the normal Tcl parser, so it is normally recommended to enclose the arguments to \fBexpr\fR in braces. Without braces, as in \fBexpr\fR $v ? [a] : [b] both \fB[a]\fR and \fB[b]\fR are evaluated before \fBexpr\fR is even called. .PP For more details on the results produced by each operator, see the documentation for C. .SS "MATH FUNCTIONS" .PP A mathematical function such as \fBsin($x)\fR is replaced with a call to an ordinary Tcl command in the \fBtcl::mathfunc\fR namespace. The evaluation of an expression such as .PP .CS \fBexpr\fR {sin($x+$y)} .CE .PP is the same in every way as the evaluation of .PP .CS \fBexpr\fR {[tcl::mathfunc::sin [\fBexpr\fR {$x+$y}]]} .CE .PP which in turn is the same as the evaluation of .PP .CS tcl::mathfunc::sin [\fBexpr\fR {$x+$y}] .CE .PP \fBtcl::mathfunc::sin\fR is resolved as described in \fBNAMESPACE RESOLUTION\fR in the \fBnamespace\fR(3tcl) documentation. Given the default value of \fBnamespace path\fR, \fB[namespace current]::tcl::mathfunc::sin\fR or \fB::tcl::mathfunc::sin\fR are the typical resolutions. .PP As in C, a mathematical function may accept multiple arguments separated by commas. Thus, .PP .CS \fBexpr\fR {hypot($x,$y)} .CE .PP becomes .PP .CS tcl::mathfunc::hypot $x $y .CE .PP See the \fBmathfunc\fR(3tcl) documentation for the math functions that are available by default. .SS "TYPES, OVERFLOW, AND PRECISION" .PP When needed to guarantee exact performance, internal computations involving integers use the LibTomMath multiple precision integer library. In Tcl releases prior to 8.5, integer calculations were performed using one of the C types \fIlong int\fR or \fITcl_WideInt\fR, causing implicit range truncation in those calculations where values overflowed the range of those types. Any code that relied on these implicit truncations should instead call \fBint()\fR or \fBwide()\fR, which do truncate. .PP Internal floating-point computations are performed using the \fIdouble\fR C type. When converting a string to floating-point value, exponent overflow is detected and results in the \fIdouble\fR value of \fBInf\fR or \fB\-Inf\fR as appropriate. Floating-point overflow and underflow are detected to the degree supported by the hardware, which is generally fairly reliable. .PP Conversion among internal representations for integer, floating-point, and string operands is done automatically as needed. For arithmetic computations, integers are used until some floating-point number is introduced, after which floating-point values are used. For example, .PP .CS \fBexpr\fR {5 / 4} .CE .PP returns 1, while .PP .CS \fBexpr\fR {5 / 4.0} \fBexpr\fR {5 / ( [string length "abcd"] + 0.0 )} .CE .PP both return 1.25. A floating-point result can be distinguished from an integer result by the presence of either .QW \fB.\fR or .QW \fBe\fR .PP . For example, .PP .CS \fBexpr\fR {20.0/5.0} .CE .PP returns \fB4.0\fR, not \fB4\fR. .SH "PERFORMANCE CONSIDERATIONS" .PP Where an expression contains syntax that Tcl would otherwise perform substitutions on, enclosing an expression in braces or otherwise quoting it so that it's a static value allows the Tcl compiler to generate bytecode for the expression, resulting in better speed and smaller storage requirements. This also avoids issues that can arise if Tcl is allowed to perform substitution on the value before \fBexpr\fR is called. .PP In the following example, the value of the expression is 11 because the Tcl parser first substitutes \fB$b\fR and \fBexpr\fR then substitutes \fB$a\fR as part of evaluating the expression .QW "$a + 2*4" . Enclosing the expression in braces would result in a syntax error as \fB$b\fR does not evaluate to a numeric value. .PP .CS set a 3 set b {$a + 2} \fBexpr\fR $b*4 .CE .PP When an expression is generated at runtime, like the one above is, the bytecode compiler must ensure that new code is generated each time the expression is evaluated. This is the most costly kind of expression from a performance perspective. In such cases, consider directly using the commands described in the \fBmathfunc\fR(3tcl) or \fBmathop\fR(3tcl) documentation instead of \fBexpr\fR. .PP Most expressions are not formed at runtime, but are literal strings or contain substitutions that don't introduce other substitutions. To allow the bytecode compiler to work with an expression as a string literal at compilation time, ensure that it contains no substitutions or that it is enclosed in braces or otherwise quoted to prevent Tcl from performing substitutions, allowing \fBexpr\fR to perform them instead. .PP If it is necessary to include a non-constant expression string within the wider context of an otherwise-constant expression, the most efficient technique is to put the varying part inside a recursive \fBexpr\fR, as this at least allows for the compilation of the outer part, though it does mean that the varying part must itself be evaluated as a separate expression. Thus, in this example the result is 20 and the outer expression benefits from fully cached bytecode compilation. .PP .CS set a 3 set b {$a + 2} \fBexpr\fR {[\fBexpr\fR $b] * 4} .CE .PP In general, you should enclose your expression in braces wherever possible, and where not possible, the argument to \fBexpr\fR should be an expression defined elsewhere as simply as possible. It is usually more efficient and safer to use other techniques (e.g., the commands in the \fBtcl::mathop\fR namespace) than it is to do complex expression generation. .SH EXAMPLES .PP A numeric comparison whose result is 1: .PP .CS \fBexpr\fR {"0x03" > "2"} .CE .PP A string comparison whose result is 1: .PP .CS \fBexpr\fR {"0y" > "0x12"} .CE .PP .VS "8.7, TIP461" A forced string comparison whose result is 0: .PP .CS \fBexpr\fR {"0x03" gt "2"} .CE .VE "8.7, TIP461" .PP Define a procedure that computes an .QW interesting mathematical function: .PP .CS proc tcl::mathfunc::calc {x y} { \fBexpr\fR { ($x**2 - $y**2) / exp($x**2 + $y**2) } } .CE .PP Convert polar coordinates into cartesian coordinates: .PP .CS # convert from ($radius,$angle) set x [\fBexpr\fR { $radius * cos($angle) }] set y [\fBexpr\fR { $radius * sin($angle) }] .CE .PP Convert cartesian coordinates into polar coordinates: .PP .CS # convert from ($x,$y) set radius [\fBexpr\fR { hypot($y, $x) }] set angle [\fBexpr\fR { atan2($y, $x) }] .CE .PP Print a message describing the relationship of two string values to each other: .PP .CS puts "a and b are [\fBexpr\fR {$a eq $b ? {equal} : {different}}]" .CE .PP Set a variable indicating whether an environment variable is defined and has value of true: .PP .CS set isTrue [\fBexpr\fR { # Does the environment variable exist, and... [info exists ::env(SOME_ENV_VAR)] && # ...does it contain a proper true value? [string is true -strict $::env(SOME_ENV_VAR)] }] .CE .PP Generate a random integer in the range 0..99 inclusive: .PP .CS set randNum [\fBexpr\fR { int(100 * rand()) }] .CE .SH "SEE ALSO" array(3tcl), for(3tcl), if(3tcl), mathfunc(3tcl), mathop(3tcl), namespace(3tcl), proc(3tcl), string(3tcl), Tcl(3tcl), while(3tcl) .SH KEYWORDS arithmetic, boolean, compare, expression, fuzzy comparison, integer value .SH COPYRIGHT .nf Copyright \(co 1993 The Regents of the University of California. Copyright \(co 1994-2000 Sun Microsystems Incorporated. Copyright \(co 2005 Kevin B. Kenny . All rights reserved. .fi '\" Local Variables: '\" mode: nroff '\" fill-column: 78 '\" End: