Expressions are used for queries, for defaults of card items, and for printing expressions into cards. They are set in Database Edit mode; a normal user does not deal with expressions directly.
Expressions deal with two data types, strings and numbers. Expressions or sub-expressions returning strings are enclosed in braces; expressions or sub-expressions returning numbers are enclosed in parentheses. There are many built-in operators and functions; most of them can be used only in either string or numeric context.
Numbers begin with a numerical digit or a period, and are in standard integer, floating-point, or exponential notation. String literals are enclosed in double quotes. Conversions from numbers to strings use the %g format (unless printf is used); conversions from strings to numbers skips leading blanks and converts like atof. Trailing non-numeric characters are ignored.
Expressions are interpreted, not compiled. This means that all parts of the expression are evaluated, ?:, &&, and || do not short-circuit.
In the following tables, n stands for a number ot a
numerical expression, and s stands for a literal string or a
string expression. Note that some operators, such as == and
date, appear in both contexts.
Divisions by zero return 1. Arithmetic operators use standard C
precedences. Bitwise operations operate on 32 bits only.
Numerical Operations
operator | type | operation |
---|---|---|
(n) | n | Number |
{s} | n | In number context, convert string to a number |
n ? n : n | n | If the first number is nonzero, return the second number; otherwise, return the third number |
n , n | n | Evaluate both numbers, return second |
- n | n | Unary minus |
! n | n | Unary boolean NOT |
~ n | n | Unary bitwise NOT |
n + n | n | Add two numbers |
n - n | n | Subtract two numbers |
n * n | n | Multiply two numbers |
n / n | n | Divide two numbers |
n % n | n | Calculate modulo of two numbers |
n & n | n | Calculate bitwise AND of two numbers |
n && n | n | Calculate boolean AND of two numbers |
n | n | n | Calculate bitwise OR of two numbers |
n || n | n | Calculate boolean OR of two numbers |
n ^ n | n | Calculate bitwise XOR of two numbers |
n << n | n | Calculate bitwise left shift |
n >> n | n | Calculate bitwise right shift |
n == n | n | 1 if both numbers are equal, 0 otherwise |
n != n | n | 1 if both numbers are not equal, 0 otherwise |
n < n | n | 1 if the first number is less than the second, 0 otherwise |
n > n | n | 1 if the first number is greater than the second, 0 otherwise |
n <= n | n | 1 if the first number is less than or equal to the second, 0 otherwise |
n >= n | n | 1 if the first number is greater than or equal to the second, 0 otherwise |
sqrt(n) | n | Square root of a number |
exp(n) | n | Exponential function, en |
log(n) | n | Decimal logarithm, log10 n |
ln(n) | n | Natural logarithm, loge n |
pow(n, n) | n | First number raised to the second, nm |
sin(n) | n | Sine of a number, sin x |
cos(n) | n | Cosine of a number, cos x |
tan(n) | n | Tangent of a number, tan x |
asin(n) | n | Arc sine of a number, sin-1 x |
acos(n) | n | Arc cosine of a number, cos-1 x |
atan(n) | n | Arctangent of a number, tan-1 x |
atan2(n, n) | n | Quadrant-aligned arc tangent |
len(s) | n | Length of a string |
bound(n, n, n) | n | The first number bounded by a minimum (second number) and a maximum (third number) |
Note that string comparisons return strings, and must be enclosed in braces {...} if && or || or other numerical operators are used on the result.
operator | type | operation |
---|---|---|
{s} | s | String |
(n) | s | In string context, convert number to a string |
s ; s | s | Evaluate both strings, return second |
s . s | s | Concatenate strings |
s ? s : s | s | If the numeric value of the first string is nonzero, return the second string; otherwise, return the third string |
s == s | s | Return "1" if the two strings match; otherwise, return "0" |
s != s | s | Return "1" if the two strings do not match; otherwise, return "0" |
s < s | s | Return "1" if the first string is lexicographically less than the second string; otherwise, return "0" |
s > s | s | Return "1" if the first string is lexicographically greater than the second string; otherwise, return "0" |
s <= s | s | Return "1" if the first string is lexicographically less than or equal to the second string; otherwise, return "0" |
s >= s | s | Return "1" if the first string is lexicographically greater than or equal to the second string; otherwise, return "0" |
s in s | s | Return "1" if the first string is contained in the second string; otherwise, return "0" |
chop(s) | s | Return the string with the trailing newline, if any, removed |
substr(s, n, n) | s | Return a substring of the first string. The first number is the start index and the second the length. A negative index counts from the end. |
printf(args) | s | Format and return a string; args is a comma-separated list of expressions. Compound expressions must be enclosed in ( ) or { }. |
Variables are letters a through z and A through Z that can hold strings or numbers. When a variable is assigned to, the result of the assignment is returned. All variables a...z are reset to the empty string (or 0) when a database is loaded from disk; variables A...Z are never automatically cleared.
operator | type | operation |
---|---|---|
var | s,n | Value of a variable |
var = s | s | Assign string value to a variable |
var = n | n | Assign numeric value to a variable |
var .= s | s | Append string to a variable |
var += n | n | Add a number to a variable |
var -= n | n | Subtract a number from a variable |
var *= n | n | Multiply a variable by a number |
var /= n | n | Divide a variable by a number |
var %= n | n | Assign modulo with a number to variable |
var &= n | n | Perform logical AND with a variable |
var |= n | n | Perform logical OR with a variable |
var++ | n | Post-increment variable |
var-- | n | Post-decrement variable |
++var | n | Pre-increment variable |
--var | n | Pre-decrement variable |
Database rows (cards) can be accessed by providing an index in brackets. Without brackets, the current card (this) is assumed. Database columns are named. The name must always be prefixed with an underscore (_). In place of the name, the field can be selected with a column number (which must also be prefixed with an underscore), beginning at 0. Only fields that store data in the database can be accessed (types Input, Time, Flag, and Choice); this excludes fields of type Label and Print. Fields can also be assigned to using the ``='' sign; the assignment returns the assigned value. Avoid assigning to fields in default and Print and other expressions that are evaluated when redrawing the card; the card is not re-redrawn if the redrawing itself changed it. It is recommended to use field assignments only in button action expressions.
The avg, dev, min, max, and sum operators differ from all other operators: they don't reference a field in the current or any single card, they operate on a field in all cards by accessing an entire column of the database. These operators are also available as qavg, qdev, qmin, qmax, and qsum, which apply the calculation only to the result of the last query (i.e., to the cards displayed in the summary). Finally, the savg, sdev, smin, smax, and qsum variations are applied to all cards in the current section; if there are no sections or if all sections are selected, all cards are considered.
The switch statement is legal only in Action when pressed expressions for Button-type fields in the form editor. It does nothing except as action for a button in a card. It switches grok to a new form as if the Database pulldown had been used (see the Editing Forms chapter for details about the difference between databases and forms. The first argument is the new form name, the second argument is the query expression or search string that determines which cards are displayed in the summary initially. The possible combinations are:
Because short-circuiting doesn't work, switch can't depend on a conditional, but its two arguments can. switch returns the empty string, which means that the button won't execute a command as usual; if this is overridden by appending a semicolon and another string expression, the command is executed after the database switch. To execute a script before switching, prepend a system statement and a semicolon to the switch statement (the switch is done after the expression is completely evaluated). To switch back to the previous form, use the prevform statement.
Looping over all cards in the database can be performed using the foreach statement. It takes either one or two arguments, both of which can bei either string or numeric expressions. In its one-argument form, it applies the argument expression to every card in the database. In its two-argument form, it applies the second argument expression to all cards that cause the first argument expression to evaluate to true (nonzero numeric value or string not beginning with ``f'' or ``F''). For example,
{(a=0); foreach("{_group == 'f'", "(a++)")}
clears the variable a and then applies the expression (a++) to all cards for which {_group == 'f'} evaluates to true. The number of cards in group f is left in variable a. Note the quotes around the argument expressions; they must be passed to the foreach statement as strings. Like all strings, they can be put together using expressions, for example using the ``.'' (dot) operator. Although foreach, like switch, can only be used in string expressions it does not return anything.
operator | type | operation |
---|---|---|
_field | s,n | A field from the database, current card |
_field[n] | s,n | A field from the database, any card |
_field = n | n | Change a field in the database, current card |
_field = s | s | Change a field in the database, current card |
_field[n] = n | n | Change a field in the database, any card |
_field[n] = s | s | Change a field in the database, any card |
expand(_field) | s | A field from the database, current card, with flag or choice value expanded to mnemonic string (*) |
expand(_field[n]) | s | A field from the database, any card, with flag or choice value expanded to mnemonic string (*) |
this | n | The number of the current card, 0 is first |
last | n | The number of the last card, 0 is first |
disp | n | The number of the currently displayed card, or -1 if none |
avg(_field) | n | Average of a field in all cards |
qavg(_field) | n | Average the current query result |
savg(_field) | n | Average the current section |
dev(_field) | n | Standard deviation of a field in all cards |
qdev(_field) | n | Std. dev. of the current query result |
sdev(_field) | n | Std. dev. of the current section |
min(_field) | n | Minimum value of a field in all cards |
qmin(_field) | n | Minimum of the current query result |
smin(_field) | n | Minimum of the current section |
max(_field) | n | Maximum value of a field in all cards |
qmax(_field) | n | Maximum value of the current query result |
smax(_field) | n | Maximum value of the current section |
sum(_field) | n | Sum of a field in all cards |
qsum(_field) | n | Sum of the current query result |
ssum(_field) | n | Sum of the current section |
dbase | s | The name of the accessed database file |
form | s | The name of the accessed form file |
section | s | The name of the current section, or the empty string |
section | n | The number of the section the current card is in, or 0 |
section[n] | s | The name of section n |
section[n] | n | The number of the section card n is in, or 0 |
prevform | s | The name of the previous accessed form file |
switch(s, s) | s | Database switch and/or query; see above |
foreach(s) | s | Apply expression to all cards; see above |
foreach(s, s) | s | Apply expression to all matching cards; see above |
(*) The expand keyword was introduced in grok version 1.5.
Operating System Access
operator | type | operation |
---|---|---|
system(s) | s | Execute a shell command and return the result as a string |
$envvar | s | Return the value of the environment variable envvar |
host | s | The host name of the local host |
user | s | The user's login name |
uid | n | The user's numeric user ID |
gid | n | The user's numeric group ID |
access(s, n) | n | 1 if the file name exists (if the number is 0), or if it can be accessed for execution (1), writing (2), and/or reading (4). See access(3). |
beep | s | Ring the terminal bell, return a null string |
error(args) | s | Format a string like printf, print it in a window, return a null string |
Dates and times are stored as number of seconds since January 1, 1970. Durations are stored as number of seconds. Note that this means thata time is a significantly larger number than a duration, even if both have the same hh:mm string representation. The representation depends on the date and time format selected in the Preferences menu. A date or time of exactly 0 (January 1, 1970, 0:00 GMT) is converted to the empty string; this convention is useful for blank date fields.
operator | type | operation |
---|---|---|
time | s | The current time as hh:mm or hh:mm[ap] string |
time(n) | s | Extract time part of the number, and format as hh:mm or hh:mm[ap] string |
time(s) | n | Convert a time string to a number of seconds |
date | s | Today's date as dd.mm.yy or mm/dd/yy string |
date | n | Current time in seconds since January 1, 1970 |
date(n) | s | Extract date part of the number, and format as dd.mm.yy or mm/dd/yy string |
date(s) | n | Convert a date or date/time string to a number of seconds |
duration(n) | s | Convert a number of seconds to a hh:mm string |
duration(s) | n | Convert a duration string to a number of seconds |
year(n) | n | Extract the (four-digit) year from a time |
month(n) | n | Extract the month 1..12 from a time |
day(n) | n | Extract the day 1..31 from a time |
hour(n) | n | Extract the hour 0..23 from a time |
minute(n) | n | Extract the minute 0..59 from a time |
second(n) | n | Extract the second 0..59 from a time |
julian(n) | n | Extract the julian date 0..365 from a time |
leap(n) | n | 1 if the time is in a leap year, or 0 otherwise |
For an action when pressed, if you want to pass arguments and run scripts etc, here is an example of a way of writing something in the ``action when pressed'' field. (It must be entered on a single line.) Note the blanks that separate arguments.
{"/bin/mailmaker \""._receipt."\" \""._senton."\" \""._partxofy."\"; xterm -geometry 85x38+109+7 -e /bin/mailsend"}
In this example, Mailmaker is a script that takes the _receipt, _senton, and _partxofy fields as arguments and composes an email with headers and body. mailsend is a script that takes the headers and body and sends it out; it runs in an xterm so it can ask you if you really want to send that mail. (This example was contributed by Pawan <pawan@generalogic.com>).