summaryrefslogtreecommitdiff
path: root/usr/src/lib/efcode/engine/env.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/efcode/engine/env.c')
-rw-r--r--usr/src/lib/efcode/engine/env.c863
1 files changed, 863 insertions, 0 deletions
diff --git a/usr/src/lib/efcode/engine/env.c b/usr/src/lib/efcode/engine/env.c
new file mode 100644
index 0000000000..e5d20ec882
--- /dev/null
+++ b/usr/src/lib/efcode/engine/env.c
@@ -0,0 +1,863 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <fcode/private.h>
+#include <fcode/log.h>
+
+
+static variable_t verbose_emit;
+
+void
+do_verbose_emit(fcode_env_t *env)
+{
+ verbose_emit ^= 1;
+}
+
+/*
+ * Internal "emit".
+ * Note log_emit gathers up characters and issues a syslog or write to
+ * error log file if enabled.
+ */
+void
+do_emit(fcode_env_t *env, uchar_t c)
+{
+ if (verbose_emit)
+ log_message(MSG_ERROR, "emit(%x)\n", c);
+
+ if (c == '\n') {
+ env->output_column = 0;
+ env->output_line++;
+ } else if (c == '\r')
+ env->output_column = 0;
+ else
+ env->output_column++;
+ if (isatty(fileno(stdout))) {
+ if ((c >= 0x20 && c <= 0x7f) || c == '\n' || c == '\r' ||
+ c == '\b')
+ putchar(c);
+ else if (c >= 0 && c < 0x20)
+ printf("@%c", c + '@');
+ else
+ printf("\\%x", c);
+ fflush(stdout);
+ }
+ log_emit(c);
+}
+
+void
+system_message(fcode_env_t *env, char *msg)
+{
+ throw_from_fclib(env, 1, msg);
+}
+
+void
+emit(fcode_env_t *env)
+{
+ fstack_t d;
+
+ CHECK_DEPTH(env, 1, "emit");
+ d = POP(DS);
+ do_emit(env, d);
+}
+
+#include <sys/time.h>
+
+/*
+ * 'key?' - abort if stdin is not a tty.
+ */
+void
+keyquestion(fcode_env_t *env)
+{
+ struct timeval timeval;
+ fd_set readfds;
+ int ret;
+
+ if (isatty(fileno(stdin))) {
+ FD_ZERO(&readfds);
+ FD_SET(fileno(stdin), &readfds);
+ timeval.tv_sec = 0;
+ timeval.tv_usec = 1000;
+ ret = select(fileno(stdin) + 1, &readfds, NULL, NULL, &timeval);
+ if (FD_ISSET(fileno(stdin), &readfds))
+ PUSH(DS, TRUE);
+ else
+ PUSH(DS, FALSE);
+ } else
+ forth_abort(env, "'key?' called in non-interactive mode");
+}
+
+/*
+ * 'key' - abort if stdin is not a tty, will block on read if char not avail.
+ */
+void
+key(fcode_env_t *env)
+{
+ uchar_t c;
+
+ if (isatty(fileno(stdin))) {
+ read(fileno(stdin), &c, 1);
+ PUSH(DS, c);
+ } else
+ forth_abort(env, "'key' called in non-interactive mode");
+}
+
+void
+type(fcode_env_t *env)
+{
+ int len;
+ char *ptr;
+
+ CHECK_DEPTH(env, 2, "type");
+ ptr = pop_a_string(env, &len);
+ while (len--)
+ do_emit(env, *ptr++);
+}
+
+void
+paren_cr(fcode_env_t *env)
+{
+ do_emit(env, '\r');
+}
+
+void
+fc_crlf(fcode_env_t *env)
+{
+ do_emit(env, '\n');
+}
+
+void
+fc_num_out(fcode_env_t *env)
+{
+ PUSH(DS, (fstack_t)(&env->output_column));
+}
+
+void
+fc_num_line(fcode_env_t *env)
+{
+ PUSH(DS, (fstack_t)(&env->output_line));
+}
+
+void
+expect(fcode_env_t *env)
+{
+ char *buf, *rbuf;
+ int len;
+
+ CHECK_DEPTH(env, 2, "expect");
+ buf = pop_a_string(env, &len);
+ read_line(env);
+ rbuf = pop_a_string(env, NULL);
+ if (rbuf) {
+ strcpy(buf, rbuf);
+ env->span = strlen(buf);
+ } else
+ env->span = 0;
+}
+
+void
+span(fcode_env_t *env)
+{
+ PUSH(DS, (fstack_t)&env->span);
+}
+
+void
+do_ms(fcode_env_t *env)
+{
+ fstack_t d;
+ timespec_t rqtp;
+
+ CHECK_DEPTH(env, 1, "ms");
+ d = POP(DS);
+ if (d) {
+ rqtp.tv_sec = 0;
+ rqtp.tv_nsec = d*1000*1000;
+ nanosleep(&rqtp, 0);
+ }
+}
+
+void
+do_get_msecs(fcode_env_t *env)
+{
+ struct timeval tp;
+ long ms;
+ timespec_t rqtp;
+
+ gettimeofday(&tp, NULL);
+ ms = (tp.tv_usec/1000) + (tp.tv_sec * 1000);
+ PUSH(DS, (fstack_t)ms);
+ rqtp.tv_sec = 0;
+ rqtp.tv_nsec = 1000*1000;
+ nanosleep(&rqtp, 0);
+}
+
+#define CMN_MSG_SIZE 256
+#define CMN_MAX_DIGITS 3
+
+typedef struct CMN_MSG_T cmn_msg_t;
+
+struct CMN_MSG_T {
+ char buf[CMN_MSG_SIZE];
+ int level;
+ int len;
+ cmn_msg_t *prev;
+ cmn_msg_t *next;
+};
+
+typedef struct CMN_FMT_T cmn_fmt_t;
+
+struct CMN_FMT_T {
+ int fwidth; /* format field width */
+ int cwidth; /* column width specified in format */
+ char format; /* format type */
+};
+
+static cmn_msg_t *root = NULL;
+static int cmn_msg_level = 0;
+
+/*
+ * validfmt()
+ *
+ * Called by fmt_str() function to validate and extract formatting
+ * information from the supplied input buffer.
+ *
+ * Supported formats are:
+ * %c - character
+ * %d - signed decimal
+ * %x - unsigned hex
+ * %s - string
+ * %ld - signed 64 bit data
+ * %lx - unsigned 64 bit data
+ * %p - unsigned 64 bit data(pointer)
+ * %% - print as single "%" character
+ *
+ * Return values are:
+ * 0 - valid formatting
+ * 1 - invalid formatting found in the input buffer
+ * -1 - NULL pointer passed in for caller's receptacle
+ *
+ *
+ * For valid formatting, caller's supplied cmn_fmt_t elements are
+ * filled in:
+ * fwidth:
+ * > 0 - returned value is the field width
+ * < 0 - returned value is negation of field width for
+ * 64 bit data formats
+ * cwidth:
+ * formatted column width(if specified), otherwise 0
+ *
+ * format:
+ * contains the formatting(single) character
+ */
+static int
+validfmt(char *fmt, cmn_fmt_t *cfstr)
+{
+ int isll = 0;
+ int *fwidth, *cwidth;
+ char *format;
+ char *dig1, *dig2;
+ char cdigs[CMN_MAX_DIGITS+1];
+
+ if (cfstr == NULL)
+ return (-1);
+
+ fwidth = &cfstr->fwidth;
+ cwidth = &cfstr->cwidth;
+ format = &cfstr->format;
+ *fwidth = *cwidth = 0;
+ *format = NULL;
+ dig1 = dig2 = NULL;
+
+ /* check for left justification character */
+ if (*fmt == '-') {
+ fmt++;
+ (*fwidth)++;
+
+ /* check for column width specification */
+ if (isdigit(*fmt))
+ dig1 = fmt; /* save ptr to first digit */
+ while (isdigit(*fmt)) {
+ fmt++;
+ (*fwidth)++;
+ }
+ /* if ljust specified w/o size, return format error */
+ if (*fwidth == 1) {
+ return (1);
+ }
+ dig2 = fmt; /* save ptr to last digit + 1 */
+ } else {
+ /* check for column width specification */
+ if (isdigit(*fmt)) {
+ dig1 = fmt; /* save ptr to first digit */
+ while (isdigit(*fmt)) {
+ fmt++;
+ (*fwidth)++;
+ }
+ dig2 = fmt; /* save ptr to last digit + 1 */
+ }
+ }
+
+ /* if a column width was specified, save it in caller's struct */
+ if (dig1) {
+ int nbytes;
+
+ nbytes = dig2 - dig1;
+ /* if too many digits in the width return error */
+ if (nbytes > CMN_MAX_DIGITS)
+ return (1);
+ strncpy(cdigs, dig1, nbytes);
+ cdigs[nbytes] = 0;
+ *cwidth = atoi(cdigs);
+ }
+
+ /* check for long format specifier */
+ if (*fmt == 'l') {
+ fmt++;
+ (*fwidth)++;
+ isll = 1;
+ }
+
+ /* process by specific format type */
+ switch (*fmt) {
+ case 'c':
+ case 's':
+ case '%':
+ if (isll)
+ return (1);
+ case 'd':
+ case 'x':
+ *format = *fmt;
+ (*fwidth)++;
+ break;
+ case 'p':
+ isll = 1; /* uses 64 bit format */
+ *format = *fmt;
+ (*fwidth)++;
+ break;
+ default:
+ return (1); /* unknown format type */
+ }
+ if (isll) {
+ *fwidth *= -1;
+ }
+ return (0);
+}
+
+/*
+ * fmt_args()
+ *
+ * Called by fmt_str() to setup arguments for subsequent snprintf()
+ * calls. For cases not involving column width limitations, processing
+ * simply POPs the data stack as required to setup caller's arg(or
+ * llarg, as appropriate). When a column width is specified for output,
+ * a temporary buffer is constructed to contain snprintf() generated
+ * output for the argument. Testing is then performed to determine if
+ * the specified column width will require truncation of the output.
+ * If so, truncation of least significant digits is performed as
+ * necessary, and caller's arg(or llarg) is adjusted to obtain the
+ * specified column width.
+ *
+ */
+
+static void
+fmt_args(fcode_env_t *env, int cw, int fw, char format, long *arg,
+ long long *llarg)
+{
+ char *cbuf;
+ char snf[3];
+ int cbsize;
+ int cnv = 10, ndigits = 0;
+
+ if (fw > 0) { /* check for normal (not long) formats */
+
+ /* initialize format string for snprintf call */
+ snf[0] = '%';
+ snf[1] = format;
+ snf[2] = 0;
+
+ /* process by format type */
+ switch (format) {
+ case 'x':
+ cnv = 16;
+ case 'd':
+ case 'c':
+ case 'p':
+ *arg = POP(DS);
+ break;
+ case 's':
+ POP(DS);
+ *arg = POP(DS);
+ break;
+ case '%':
+ return;
+ default:
+ log_message(MSG_ERROR,
+ "fmt_args:invalid format type! (%s)\n",
+ &format);
+ return;
+ }
+
+ /* check if a column width was specified */
+ if (cw) {
+ /* allocate a scratch buffer */
+ cbsize = 2*(sizeof (long long)) + 1;
+ cbuf = MALLOC(cbsize);
+
+ if (snprintf(cbuf, cbsize, snf, *arg) < 0)
+ log_message(MSG_ERROR,
+ "fmt_args: snprintf output error\n");
+ while ((cbuf[ndigits] != NULL) &&
+ (ndigits < cbsize))
+ ndigits++;
+
+ /* if truncation is necessary, do it */
+ if (ndigits > cw) {
+ cbuf[cw] = 0;
+ if (format == 's') {
+ char *str;
+ str = (char *)*arg;
+ str[cw] = 0;
+ } else
+ *arg = strtol(cbuf,
+ (char **)NULL, cnv);
+ }
+ free(cbuf);
+ }
+
+ } else { /* process long formats */
+
+ *llarg = POP(DS);
+
+ /* check if a column width was specified */
+ if (cw) {
+ /* allocate a scratch buffer */
+ cbsize = 2*(sizeof (long long)) + 1;
+ cbuf = MALLOC(cbsize);
+
+ switch (format) {
+ case 'p':
+ cnv = 16;
+ if (snprintf(cbuf, cbsize, "%p", *llarg) < 0)
+ log_message(MSG_ERROR,
+ "fmt_args: snprintf error\n");
+ break;
+ case 'x':
+ cnv = 16;
+ if (snprintf(cbuf, cbsize, "%lx", *llarg) < 0)
+ log_message(MSG_ERROR,
+ "fmt_args: snprintf error\n");
+ break;
+ case 'd':
+ if (snprintf(cbuf, cbsize, "%ld", *llarg) < 0)
+ log_message(MSG_ERROR,
+ "fmt_args: snprintf error\n");
+ break;
+ default:
+ log_message(MSG_ERROR,
+ "invalid long format type! (l%s)\n",
+ &format);
+ free(cbuf);
+ return;
+ }
+ while ((cbuf[ndigits] != NULL) &&
+ (ndigits < cbsize)) {
+ ndigits++;
+ }
+ /* if truncation is necessary, do it */
+ if (ndigits > cw) {
+ cbuf[cw] = 0;
+ *llarg = strtoll(cbuf, (char **)NULL, cnv);
+ }
+ free(cbuf);
+ }
+ }
+}
+
+/*
+ * fmt_str()
+ *
+ * Extracts text from caller's input buffer, processes explicit
+ * formatting as necessary, and outputs formatted text to caller's
+ * receptacle.
+ *
+ * env - pointer to caller's fcode environment
+ * fmt - pointer to caller's input buffr
+ * fmtbuf - ponter to caller's receptacle buffer
+ * bsize - size of caller's fmtbuf buffer
+ *
+ * This function performs an initial test to determine if caller's
+ * input buffer contains formatting(specified by presence of "%")
+ * in the buffer. If so, validfmt() function is called to verify
+ * the formatting, after which the buffer is processed according
+ * to the field width specified by validfmt() output. Special
+ * processing is required when caller's buffer contains a double
+ * "%" ("%%"), in which case the second "%" is accepted as normal
+ * text.
+ */
+
+static void
+fmt_str(fcode_env_t *env, char *fmt, char *fmtbuf, int bsize)
+{
+ char tbuf[CMN_MSG_SIZE];
+ char *fmptr, *pct;
+ int l, cw, fw, bytes;
+ long arg;
+ long long llarg;
+
+ *fmtbuf = 0;
+ if ((pct = strchr(fmt, '%')) != 0) {
+ cmn_fmt_t cfstr;
+ int vferr;
+
+ l = strlen(pct++);
+ vferr = validfmt(pct, &cfstr);
+ if (!vferr) {
+ fw = cfstr.fwidth;
+ cw = cfstr.cwidth;
+ fmptr = &cfstr.format;
+ } else {
+ if (vferr < 0) {
+ log_message(MSG_ERROR,
+ "fmt_str: NULL ptr supplied to validfmt()\n");
+ return;
+ }
+
+ bytes = pct - fmt;
+ strncpy(tbuf, fmt, bytes);
+ strncpy(tbuf+bytes, "%", 1);
+ strncpy(tbuf+bytes+1, fmt+bytes, 1);
+ bytes += 2;
+ tbuf[bytes] = 0;
+
+ log_message(MSG_ERROR,
+ "fmt_str: invalid format type! (%s)\n",
+ tbuf+bytes-3);
+
+ strncpy(fmtbuf, tbuf, bsize);
+ return;
+ }
+
+ if (fw > 0) { /* process normal (not long) formats */
+ bytes = pct - fmt + fw;
+ strncpy(tbuf, fmt, bytes);
+ tbuf[bytes] = 0;
+ } else {
+ /* if here, fw must be a long format */
+ if (*fmptr == 'p') {
+ bytes = pct - fmt - fw;
+ strncpy(tbuf, fmt, bytes);
+ tbuf[bytes] = 0;
+ } else {
+ bytes = pct - fmt - fw - 2;
+ strncpy(tbuf, fmt, bytes);
+ tbuf[bytes] = 'l';
+ strncpy(tbuf+bytes+1, fmt+bytes, 2);
+ tbuf[bytes+1+2] = 0;
+ }
+ }
+
+ /* if more input buffer to process, recurse */
+ if ((l - abs(fw)) != 0) {
+ fmt_str(env, pct+abs(fw), (tbuf + strlen(tbuf)),
+ CMN_MSG_SIZE - strlen(tbuf));
+ }
+
+ /* call to extract args for snprintf() calls below */
+ fmt_args(env, cw, fw, *fmptr, &arg, &llarg);
+
+ if (fw > 0) { /* process normal (not long) formats */
+ switch (*fmptr) {
+ case 'd':
+ case 'x':
+ case 'c':
+ case 's':
+ case 'p':
+ (void) snprintf(fmtbuf, bsize, tbuf, arg);
+ break;
+ case '%':
+ (void) snprintf(fmtbuf, bsize, tbuf);
+ break;
+ default:
+ log_message(MSG_ERROR,
+ "fmt_str: invalid format (%s)\n",
+ fmptr);
+ return;
+ }
+
+ } else /* process long formats */
+ (void) snprintf(fmtbuf, bsize, tbuf, llarg);
+
+ } else
+ strncpy(fmtbuf, fmt, bsize);
+}
+
+/*
+ * fc_cmn_append()
+ *
+ * Pops data stack to obtain message text, and calls fmt_str()
+ * function to perform any message formatting necessary.
+ *
+ * This function is called from fc_cmn_end() or directly in
+ * processing a cmn-append token. Since a pre-existing message
+ * context is assumed, initial checking is performed to verify
+ * its existence.
+ */
+
+void
+fc_cmn_append(fcode_env_t *env)
+{
+ int len;
+ char *str;
+
+ if (root == NULL) {
+ log_message(MSG_ERROR,
+ "fc_cmn_append: no message context for append\n");
+ return;
+ }
+
+ len = POP(DS);
+ str = (char *)POP(DS);
+
+ if ((root->len + len) < CMN_MSG_SIZE) {
+ fmt_str(env, str, root->buf+root->len, CMN_MSG_SIZE -
+ root->len);
+ root->len += len;
+ } else
+ log_message(MSG_ERROR,
+ "fc_cmn_append: append exceeds max msg size\n");
+}
+
+/*
+ * fc_cmn_end()
+ *
+ * Process ]cmn-end token to log the message initiated by a preceeding
+ * fc_cmn_start() call.
+ *
+ * Since nested cmn-xxx[ calls are supported, a test is made to determine
+ * if this is the final cmn-end of a nested sequence. If so, or if
+ * there was no nesting, log_message() is called with the appropriate
+ * text buffer. Otherwise, the root variable is adjusted to point to
+ * the preceeding message in the sequence and links in the list are
+ * updated. No logging is performed until the final ]cmn-end of the
+ * sequence is processed; then, messages are logged in FIFO order.
+ */
+void
+fc_cmn_end(fcode_env_t *env)
+{
+ cmn_msg_t *old;
+
+ if (root == 0) {
+ log_message(MSG_ERROR, "]cmn-end call w/o buffer\n");
+ return;
+ }
+
+ fc_cmn_append(env);
+
+ if (root->prev == 0) {
+ cmn_msg_t *next;
+ do {
+ log_message(root->level, "%s\n", root->buf);
+ next = root->next;
+ free(root);
+ root = next;
+ } while (root);
+ } else {
+ old = root->prev;
+ old->next = root;
+ root = old;
+ }
+}
+
+/*
+ * fc_cmn_start()
+ *
+ * Generic function to begin a common message.
+ *
+ * Allocates a new cmn_msg_t to associate with the message, and sets
+ * up initial text as specified by callers' inputs:
+ *
+ * env - pointer to caller's fcode environment
+ * head - pointer to initial text portion of the message
+ * path - flag to indicate if a device path is to be generated
+ */
+static void
+fc_cmn_start(fcode_env_t *env, char *head, int path)
+{
+ cmn_msg_t *new;
+ char *dpath;
+
+ new = MALLOC(sizeof (cmn_msg_t));
+ new->prev = root;
+ if (root != 0)
+ root->next = new;
+ strcpy(new->buf, head);
+ new->len = strlen(head);
+ if (path && env->current_device) {
+ dpath = get_path(env, env->current_device);
+ strcpy(new->buf+new->len, dpath);
+ new->len += strlen(dpath);
+ strncpy(new->buf+new->len++, ": ", 2);
+ ++new->len;
+ free(dpath);
+ }
+ new->level = cmn_msg_level;
+ new->next = NULL;
+ root = new;
+}
+
+/*
+ * fc_cmn_type()
+ *
+ * Process cmn-type[ token.
+ *
+ * Invokes fc_cmn_start() to create a message containing blank
+ * header and no device path information.
+ */
+void
+fc_cmn_type(fcode_env_t *env)
+{
+ cmn_msg_level = MSG_INFO;
+ fc_cmn_start(env, "", 0);
+}
+
+/*
+ * fc_cmn_msg()
+ *
+ * Process cmn-msg[ token.
+ *
+ * Invokes fc_cmn_start() to create a message containing blank
+ * header but specifying device path information.
+ */
+void
+fc_cmn_msg(fcode_env_t *env)
+{
+
+ cmn_msg_level = MSG_INFO;
+ fc_cmn_start(env, "", 1);
+}
+
+/*
+ * fc_cmn_note()
+ *
+ * Process cmn-note[ token.
+ *
+ * Invokes fc_cmn_start() to create a message with NOTICE stamping in
+ * the header and specification of device path information.
+ */
+void
+fc_cmn_note(fcode_env_t *env)
+{
+ cmn_msg_level = MSG_NOTE;
+ fc_cmn_start(env, "NOTICE: ", 1);
+}
+
+/*
+ * fc_cmn_warn()
+ *
+ * Process cmn-warn[ token.
+ *
+ * Invokes fc_cmn_start() to create a message with WARNING stamping in
+ * the header and specification of device path information.
+ */
+void
+fc_cmn_warn(fcode_env_t *env)
+{
+ cmn_msg_level = MSG_WARN;
+ fc_cmn_start(env, "WARNING: ", 1);
+}
+
+/*
+ * fc_cmn_error()
+ *
+ * Process cmn-error[ token.
+ *
+ * Invokes fc_cmn_start() to create a message with ERROR stamping in
+ * the header and specification of device path information.
+ */
+void
+fc_cmn_error(fcode_env_t *env)
+{
+ cmn_msg_level = MSG_ERROR;
+ fc_cmn_start(env, "ERROR: ", 1);
+}
+
+/*
+ * fc_cmn_fatal()
+ *
+ * Process cmn-fatal[ token.
+ *
+ * Invokes fc_cmn_start() to create a message with FATAL stamping in
+ * the header and specification of device path information.
+ */
+void
+fc_cmn_fatal(fcode_env_t *env)
+{
+ cmn_msg_level = MSG_FATAL;
+ fc_cmn_start(env, "FATAL: ", 1);
+}
+
+#pragma init(_init)
+
+static void
+_init(void)
+{
+ fcode_env_t *env = initial_env;
+ ASSERT(env);
+ NOTICE;
+
+ ANSI(0x088, 0, "span", span);
+ ANSI(0x08a, 0, "expect", expect);
+
+ ANSI(0x08d, 0, "key?", keyquestion);
+ ANSI(0x08e, 0, "key", key);
+ ANSI(0x08f, 0, "emit", emit);
+ ANSI(0x090, 0, "type", type);
+ ANSI(0x091, 0, "(cr", paren_cr);
+ ANSI(0x092, 0, "cr", fc_crlf);
+ ANSI(0x093, 0, "#out", fc_num_out);
+ ANSI(0x094, 0, "#line", fc_num_line);
+
+ FCODE(0x125, 0, "get-msecs", do_get_msecs);
+ FCODE(0x126, 0, "ms", do_ms);
+
+ FORTH(0, "verbose-emit", do_verbose_emit);
+ FCODE(0x7e9, 0, "cmn-fatal[", fc_cmn_fatal);
+ FCODE(0x7ea, 0, "cmn-error[", fc_cmn_error);
+ FCODE(0x7eb, 0, "cmn-warn[", fc_cmn_warn);
+ FCODE(0x7ec, 0, "cmn-note[", fc_cmn_note);
+ FCODE(0x7ed, 0, "cmn-type[", fc_cmn_type);
+ FCODE(0x7ee, 0, "cmn-append", fc_cmn_append);
+ FCODE(0x7ef, 0, "]cmn-end", fc_cmn_end);
+ FCODE(0x7f0, 0, "cmn-msg[", fc_cmn_msg);
+}