xref: /illumos-gate/usr/src/lib/efcode/engine/env.c (revision 09e6639b)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <ctype.h>
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <unistd.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <sys/time.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <fcode/private.h>
357c478bd9Sstevel@tonic-gate #include <fcode/log.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static variable_t verbose_emit;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate void
do_verbose_emit(fcode_env_t * env)417c478bd9Sstevel@tonic-gate do_verbose_emit(fcode_env_t *env)
427c478bd9Sstevel@tonic-gate {
437c478bd9Sstevel@tonic-gate 	verbose_emit ^= 1;
447c478bd9Sstevel@tonic-gate }
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
477c478bd9Sstevel@tonic-gate  * Internal "emit".
487c478bd9Sstevel@tonic-gate  * Note log_emit gathers up characters and issues a syslog or write to
497c478bd9Sstevel@tonic-gate  * error log file if enabled.
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate void
do_emit(fcode_env_t * env,uchar_t c)527c478bd9Sstevel@tonic-gate do_emit(fcode_env_t *env, uchar_t c)
537c478bd9Sstevel@tonic-gate {
547c478bd9Sstevel@tonic-gate 	if (verbose_emit)
557c478bd9Sstevel@tonic-gate 		log_message(MSG_ERROR, "emit(%x)\n", c);
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate 	if (c == '\n') {
587c478bd9Sstevel@tonic-gate 		env->output_column = 0;
597c478bd9Sstevel@tonic-gate 		env->output_line++;
607c478bd9Sstevel@tonic-gate 	} else if (c == '\r')
617c478bd9Sstevel@tonic-gate 		env->output_column = 0;
627c478bd9Sstevel@tonic-gate 	else
637c478bd9Sstevel@tonic-gate 		env->output_column++;
647c478bd9Sstevel@tonic-gate 	if (isatty(fileno(stdout))) {
657c478bd9Sstevel@tonic-gate 		if ((c >= 0x20 && c <= 0x7f) || c == '\n' || c == '\r' ||
667c478bd9Sstevel@tonic-gate 		    c == '\b')
67*09e6639bSToomas Soome 			(void) putchar(c);
68360e6f5eSmathue 		else if (c < 0x20)
697c478bd9Sstevel@tonic-gate 			printf("@%c", c + '@');
707c478bd9Sstevel@tonic-gate 		else
717c478bd9Sstevel@tonic-gate 			printf("\\%x", c);
727c478bd9Sstevel@tonic-gate 		fflush(stdout);
737c478bd9Sstevel@tonic-gate 	}
747c478bd9Sstevel@tonic-gate 	log_emit(c);
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate void
system_message(fcode_env_t * env,char * msg)787c478bd9Sstevel@tonic-gate system_message(fcode_env_t *env, char *msg)
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate 	throw_from_fclib(env, 1, msg);
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate void
emit(fcode_env_t * env)847c478bd9Sstevel@tonic-gate emit(fcode_env_t *env)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	fstack_t d;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	CHECK_DEPTH(env, 1, "emit");
897c478bd9Sstevel@tonic-gate 	d = POP(DS);
907c478bd9Sstevel@tonic-gate 	do_emit(env, d);
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #include <sys/time.h>
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * 'key?' - abort if stdin is not a tty.
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate void
keyquestion(fcode_env_t * env)997c478bd9Sstevel@tonic-gate keyquestion(fcode_env_t *env)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	struct timeval timeval;
1027c478bd9Sstevel@tonic-gate 	fd_set readfds;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	if (isatty(fileno(stdin))) {
1057c478bd9Sstevel@tonic-gate 		FD_ZERO(&readfds);
1067c478bd9Sstevel@tonic-gate 		FD_SET(fileno(stdin), &readfds);
1077c478bd9Sstevel@tonic-gate 		timeval.tv_sec = 0;
1087c478bd9Sstevel@tonic-gate 		timeval.tv_usec = 1000;
109*09e6639bSToomas Soome 		(void) select(fileno(stdin) + 1, &readfds, NULL, NULL,
110*09e6639bSToomas Soome 		    &timeval);
1117c478bd9Sstevel@tonic-gate 		if (FD_ISSET(fileno(stdin), &readfds))
1127c478bd9Sstevel@tonic-gate 			PUSH(DS, TRUE);
1137c478bd9Sstevel@tonic-gate 		else
1147c478bd9Sstevel@tonic-gate 			PUSH(DS, FALSE);
1157c478bd9Sstevel@tonic-gate 	} else
1167c478bd9Sstevel@tonic-gate 		forth_abort(env, "'key?' called in non-interactive mode");
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate  * 'key' - abort if stdin is not a tty, will block on read if char not avail.
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate void
key(fcode_env_t * env)1237c478bd9Sstevel@tonic-gate key(fcode_env_t *env)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate 	uchar_t c;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	if (isatty(fileno(stdin))) {
128*09e6639bSToomas Soome 		(void) read(fileno(stdin), &c, 1);
1297c478bd9Sstevel@tonic-gate 		PUSH(DS, c);
1307c478bd9Sstevel@tonic-gate 	} else
1317c478bd9Sstevel@tonic-gate 		forth_abort(env, "'key' called in non-interactive mode");
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate void
type(fcode_env_t * env)1357c478bd9Sstevel@tonic-gate type(fcode_env_t *env)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate 	int len;
1387c478bd9Sstevel@tonic-gate 	char *ptr;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	CHECK_DEPTH(env, 2, "type");
1417c478bd9Sstevel@tonic-gate 	ptr = pop_a_string(env, &len);
1427c478bd9Sstevel@tonic-gate 	while (len--)
1437c478bd9Sstevel@tonic-gate 		do_emit(env, *ptr++);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate void
paren_cr(fcode_env_t * env)1477c478bd9Sstevel@tonic-gate paren_cr(fcode_env_t *env)
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate 	do_emit(env, '\r');
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate void
fc_crlf(fcode_env_t * env)1537c478bd9Sstevel@tonic-gate fc_crlf(fcode_env_t *env)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	do_emit(env, '\n');
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate void
fc_num_out(fcode_env_t * env)1597c478bd9Sstevel@tonic-gate fc_num_out(fcode_env_t *env)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	PUSH(DS, (fstack_t)(&env->output_column));
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate void
fc_num_line(fcode_env_t * env)1657c478bd9Sstevel@tonic-gate fc_num_line(fcode_env_t *env)
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate 	PUSH(DS, (fstack_t)(&env->output_line));
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate void
expect(fcode_env_t * env)1717c478bd9Sstevel@tonic-gate expect(fcode_env_t *env)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	char *buf, *rbuf;
1747c478bd9Sstevel@tonic-gate 	int len;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	CHECK_DEPTH(env, 2, "expect");
1777c478bd9Sstevel@tonic-gate 	buf = pop_a_string(env, &len);
1787c478bd9Sstevel@tonic-gate 	read_line(env);
1797c478bd9Sstevel@tonic-gate 	rbuf = pop_a_string(env, NULL);
1807c478bd9Sstevel@tonic-gate 	if (rbuf) {
181*09e6639bSToomas Soome 		(void) strcpy(buf, rbuf);
1827c478bd9Sstevel@tonic-gate 		env->span = strlen(buf);
1837c478bd9Sstevel@tonic-gate 	} else
1847c478bd9Sstevel@tonic-gate 		env->span = 0;
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate void
span(fcode_env_t * env)1887c478bd9Sstevel@tonic-gate span(fcode_env_t *env)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	PUSH(DS, (fstack_t)&env->span);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate void
do_ms(fcode_env_t * env)1947c478bd9Sstevel@tonic-gate do_ms(fcode_env_t *env)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	fstack_t d;
1977c478bd9Sstevel@tonic-gate 	timespec_t rqtp;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	CHECK_DEPTH(env, 1, "ms");
2007c478bd9Sstevel@tonic-gate 	d = POP(DS);
2017c478bd9Sstevel@tonic-gate 	if (d) {
2027c478bd9Sstevel@tonic-gate 		rqtp.tv_sec = 0;
2037c478bd9Sstevel@tonic-gate 		rqtp.tv_nsec = d*1000*1000;
204*09e6639bSToomas Soome 		(void) nanosleep(&rqtp, 0);
2057c478bd9Sstevel@tonic-gate 	}
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate void
do_get_msecs(fcode_env_t * env)2097c478bd9Sstevel@tonic-gate do_get_msecs(fcode_env_t *env)
2107c478bd9Sstevel@tonic-gate {
2117c478bd9Sstevel@tonic-gate 	struct timeval tp;
2127c478bd9Sstevel@tonic-gate 	long ms;
2137c478bd9Sstevel@tonic-gate 	timespec_t rqtp;
2147c478bd9Sstevel@tonic-gate 
215*09e6639bSToomas Soome 	(void) gettimeofday(&tp, NULL);
2167c478bd9Sstevel@tonic-gate 	ms = (tp.tv_usec/1000) + (tp.tv_sec * 1000);
2177c478bd9Sstevel@tonic-gate 	PUSH(DS, (fstack_t)ms);
2187c478bd9Sstevel@tonic-gate 	rqtp.tv_sec = 0;
2197c478bd9Sstevel@tonic-gate 	rqtp.tv_nsec = 1000*1000;
220*09e6639bSToomas Soome 	(void) nanosleep(&rqtp, 0);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate #define	CMN_MSG_SIZE	256
2247c478bd9Sstevel@tonic-gate #define	CMN_MAX_DIGITS	3
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate typedef struct CMN_MSG_T cmn_msg_t;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate struct CMN_MSG_T {
2297c478bd9Sstevel@tonic-gate 	char		buf[CMN_MSG_SIZE];
2307c478bd9Sstevel@tonic-gate 	int		level;
23128e0ac9cSToomas Soome 	int		len;
2327c478bd9Sstevel@tonic-gate 	cmn_msg_t	*prev;
2337c478bd9Sstevel@tonic-gate 	cmn_msg_t	*next;
2347c478bd9Sstevel@tonic-gate };
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate typedef struct CMN_FMT_T cmn_fmt_t;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate struct CMN_FMT_T {
2397c478bd9Sstevel@tonic-gate 	int	fwidth;	/* format field width */
2407c478bd9Sstevel@tonic-gate 	int	cwidth; /* column width specified in format */
2417c478bd9Sstevel@tonic-gate 	char	format; /* format type */
2427c478bd9Sstevel@tonic-gate };
2437c478bd9Sstevel@tonic-gate 
24428e0ac9cSToomas Soome static cmn_msg_t	*root = NULL;
2457c478bd9Sstevel@tonic-gate static int		cmn_msg_level = 0;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate /*
2487c478bd9Sstevel@tonic-gate  *	validfmt()
2497c478bd9Sstevel@tonic-gate  *
2507c478bd9Sstevel@tonic-gate  * Called by fmt_str() function to validate and extract formatting
2517c478bd9Sstevel@tonic-gate  * information from the supplied input buffer.
2527c478bd9Sstevel@tonic-gate  *
2537c478bd9Sstevel@tonic-gate  * Supported formats are:
2547c478bd9Sstevel@tonic-gate  *	%c - character
2557c478bd9Sstevel@tonic-gate  *	%d - signed decimal
2567c478bd9Sstevel@tonic-gate  *	%x - unsigned hex
2577c478bd9Sstevel@tonic-gate  *	%s - string
2587c478bd9Sstevel@tonic-gate  *	%ld - signed 64 bit data
2597c478bd9Sstevel@tonic-gate  *	%lx - unsigned 64 bit data
2607c478bd9Sstevel@tonic-gate  *	%p - unsigned 64 bit data(pointer)
2617c478bd9Sstevel@tonic-gate  *	%% - print as single "%" character
2627c478bd9Sstevel@tonic-gate  *
2637c478bd9Sstevel@tonic-gate  * Return values are:
2647c478bd9Sstevel@tonic-gate  *	0  - valid formatting
2657c478bd9Sstevel@tonic-gate  *	1  - invalid formatting found in the input buffer
2667c478bd9Sstevel@tonic-gate  *	-1 - NULL pointer passed in for caller's receptacle
2677c478bd9Sstevel@tonic-gate  *
2687c478bd9Sstevel@tonic-gate  *
2697c478bd9Sstevel@tonic-gate  * For valid formatting, caller's supplied cmn_fmt_t elements are
2707c478bd9Sstevel@tonic-gate  * filled in:
2717c478bd9Sstevel@tonic-gate  *	fwidth:
27228e0ac9cSToomas Soome  *		> 0 - returned value is the field width
2737c478bd9Sstevel@tonic-gate  *		< 0 - returned value is negation of field width for
2747c478bd9Sstevel@tonic-gate  *			64 bit data formats
2757c478bd9Sstevel@tonic-gate  *	cwidth:
2767c478bd9Sstevel@tonic-gate  *	  formatted column width(if specified), otherwise 0
2777c478bd9Sstevel@tonic-gate  *
2787c478bd9Sstevel@tonic-gate  *	format:
2797c478bd9Sstevel@tonic-gate  *	  contains the formatting(single) character
2807c478bd9Sstevel@tonic-gate  */
2817c478bd9Sstevel@tonic-gate static int
validfmt(char * fmt,cmn_fmt_t * cfstr)2827c478bd9Sstevel@tonic-gate validfmt(char *fmt, cmn_fmt_t *cfstr)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate 	int	isll = 0;
2857c478bd9Sstevel@tonic-gate 	int	*fwidth, *cwidth;
2867c478bd9Sstevel@tonic-gate 	char	*format;
2877c478bd9Sstevel@tonic-gate 	char	*dig1, *dig2;
2887c478bd9Sstevel@tonic-gate 	char	cdigs[CMN_MAX_DIGITS+1];
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	if (cfstr == NULL)
2917c478bd9Sstevel@tonic-gate 		return (-1);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	fwidth = &cfstr->fwidth;
2947c478bd9Sstevel@tonic-gate 	cwidth = &cfstr->cwidth;
2957c478bd9Sstevel@tonic-gate 	format = &cfstr->format;
2967c478bd9Sstevel@tonic-gate 	*fwidth = *cwidth = 0;
29728e0ac9cSToomas Soome 	*format = '\0';
2987c478bd9Sstevel@tonic-gate 	dig1 = dig2 = NULL;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	/* check for left justification character */
3017c478bd9Sstevel@tonic-gate 	if (*fmt == '-') {
3027c478bd9Sstevel@tonic-gate 		fmt++;
3037c478bd9Sstevel@tonic-gate 		(*fwidth)++;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 		/* check for column width specification */
3067c478bd9Sstevel@tonic-gate 		if (isdigit(*fmt))
3077c478bd9Sstevel@tonic-gate 			dig1 = fmt;	/* save ptr to first digit */
3087c478bd9Sstevel@tonic-gate 		while (isdigit(*fmt)) {
3097c478bd9Sstevel@tonic-gate 			fmt++;
3107c478bd9Sstevel@tonic-gate 			(*fwidth)++;
3117c478bd9Sstevel@tonic-gate 		}
3127c478bd9Sstevel@tonic-gate 		/* if ljust specified w/o size, return format error */
3137c478bd9Sstevel@tonic-gate 		if (*fwidth == 1) {
3147c478bd9Sstevel@tonic-gate 			return (1);
3157c478bd9Sstevel@tonic-gate 		}
3167c478bd9Sstevel@tonic-gate 		dig2 = fmt;		/* save ptr to last digit + 1 */
3177c478bd9Sstevel@tonic-gate 	} else {
3187c478bd9Sstevel@tonic-gate 		/* check for column width specification */
3197c478bd9Sstevel@tonic-gate 		if (isdigit(*fmt)) {
3207c478bd9Sstevel@tonic-gate 			dig1 = fmt;	/* save ptr to first digit */
3217c478bd9Sstevel@tonic-gate 			while (isdigit(*fmt)) {
3227c478bd9Sstevel@tonic-gate 				fmt++;
3237c478bd9Sstevel@tonic-gate 				(*fwidth)++;
3247c478bd9Sstevel@tonic-gate 			}
3257c478bd9Sstevel@tonic-gate 			dig2 = fmt;	/* save ptr to last digit + 1 */
3267c478bd9Sstevel@tonic-gate 		}
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	/* if a column width was specified, save it in caller's struct */
3307c478bd9Sstevel@tonic-gate 	if (dig1) {
3317c478bd9Sstevel@tonic-gate 		int nbytes;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 		nbytes = dig2 - dig1;
3347c478bd9Sstevel@tonic-gate 		/* if too many digits in the width return error */
3357c478bd9Sstevel@tonic-gate 		if (nbytes > CMN_MAX_DIGITS)
3367c478bd9Sstevel@tonic-gate 			return (1);
337*09e6639bSToomas Soome 		(void) strncpy(cdigs, dig1, nbytes);
3387c478bd9Sstevel@tonic-gate 		cdigs[nbytes] = 0;
3397c478bd9Sstevel@tonic-gate 		*cwidth = atoi(cdigs);
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/* check for long format specifier */
3437c478bd9Sstevel@tonic-gate 	if (*fmt == 'l') {
3447c478bd9Sstevel@tonic-gate 		fmt++;
3457c478bd9Sstevel@tonic-gate 		(*fwidth)++;
3467c478bd9Sstevel@tonic-gate 		isll = 1;
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	/* process by specific format type */
3507c478bd9Sstevel@tonic-gate 	switch (*fmt) {
3517c478bd9Sstevel@tonic-gate 	case 'c':
3527c478bd9Sstevel@tonic-gate 	case 's':
3537c478bd9Sstevel@tonic-gate 	case '%':
3547c478bd9Sstevel@tonic-gate 		if (isll)
3557c478bd9Sstevel@tonic-gate 			return (1);
356*09e6639bSToomas Soome 		/* FALLTHROUGH */
3577c478bd9Sstevel@tonic-gate 	case 'd':
3587c478bd9Sstevel@tonic-gate 	case 'x':
3597c478bd9Sstevel@tonic-gate 		*format = *fmt;
3607c478bd9Sstevel@tonic-gate 		(*fwidth)++;
3617c478bd9Sstevel@tonic-gate 		break;
3627c478bd9Sstevel@tonic-gate 	case 'p':
36328e0ac9cSToomas Soome 		isll = 1;		/* uses 64 bit format */
3647c478bd9Sstevel@tonic-gate 		*format = *fmt;
3657c478bd9Sstevel@tonic-gate 		(*fwidth)++;
3667c478bd9Sstevel@tonic-gate 		break;
3677c478bd9Sstevel@tonic-gate 	default:
3687c478bd9Sstevel@tonic-gate 		return (1);		/* unknown format type */
3697c478bd9Sstevel@tonic-gate 	}
3707c478bd9Sstevel@tonic-gate 	if (isll) {
3717c478bd9Sstevel@tonic-gate 		*fwidth *= -1;
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 	return (0);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate  *	fmt_args()
3787c478bd9Sstevel@tonic-gate  *
3797c478bd9Sstevel@tonic-gate  * Called by fmt_str() to setup arguments for subsequent snprintf()
3807c478bd9Sstevel@tonic-gate  * calls.  For cases not involving column width limitations, processing
3817c478bd9Sstevel@tonic-gate  * simply POPs the data stack as required to setup caller's arg(or
3827c478bd9Sstevel@tonic-gate  * llarg, as appropriate). When a column width is specified for output,
3837c478bd9Sstevel@tonic-gate  * a temporary buffer is constructed to contain snprintf() generated
3847c478bd9Sstevel@tonic-gate  * output for the argument. Testing is then performed to determine if
3857c478bd9Sstevel@tonic-gate  * the specified column width will require truncation of the output.
3867c478bd9Sstevel@tonic-gate  * If so, truncation of least significant digits is performed as
3877c478bd9Sstevel@tonic-gate  * necessary, and caller's arg(or llarg) is adjusted to obtain the
3887c478bd9Sstevel@tonic-gate  * specified column width.
3897c478bd9Sstevel@tonic-gate  *
3907c478bd9Sstevel@tonic-gate  */
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate static void
fmt_args(fcode_env_t * env,int cw,int fw,char format,long * arg,long long * llarg)3937c478bd9Sstevel@tonic-gate fmt_args(fcode_env_t *env, int cw, int fw, char format, long *arg,
39428e0ac9cSToomas Soome     long long *llarg)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	char	*cbuf;
3977c478bd9Sstevel@tonic-gate 	char	snf[3];
3987c478bd9Sstevel@tonic-gate 	int	cbsize;
3997c478bd9Sstevel@tonic-gate 	int	cnv = 10, ndigits = 0;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	if (fw > 0) {	/* check for normal (not long) formats */
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 		/* initialize format string for snprintf call */
4047c478bd9Sstevel@tonic-gate 		snf[0] = '%';
4057c478bd9Sstevel@tonic-gate 		snf[1] = format;
4067c478bd9Sstevel@tonic-gate 		snf[2] = 0;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 		/* process by format type */
4097c478bd9Sstevel@tonic-gate 		switch (format) {
4107c478bd9Sstevel@tonic-gate 		case 'x':
4117c478bd9Sstevel@tonic-gate 			cnv = 16;
412*09e6639bSToomas Soome 			/* FALLTHROUGH */
4137c478bd9Sstevel@tonic-gate 		case 'd':
4147c478bd9Sstevel@tonic-gate 		case 'c':
4157c478bd9Sstevel@tonic-gate 		case 'p':
4167c478bd9Sstevel@tonic-gate 			*arg = POP(DS);
4177c478bd9Sstevel@tonic-gate 			break;
4187c478bd9Sstevel@tonic-gate 		case 's':
4197c478bd9Sstevel@tonic-gate 			POP(DS);
4207c478bd9Sstevel@tonic-gate 			*arg = POP(DS);
4217c478bd9Sstevel@tonic-gate 			break;
4227c478bd9Sstevel@tonic-gate 		case '%':
4237c478bd9Sstevel@tonic-gate 			return;
4247c478bd9Sstevel@tonic-gate 		default:
4257c478bd9Sstevel@tonic-gate 			log_message(MSG_ERROR,
42628e0ac9cSToomas Soome 			    "fmt_args:invalid format type! (%s)\n",
42728e0ac9cSToomas Soome 			    &format);
4287c478bd9Sstevel@tonic-gate 			return;
4297c478bd9Sstevel@tonic-gate 		}
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 		/* check if a column width was specified */
4327c478bd9Sstevel@tonic-gate 		if (cw) {
4337c478bd9Sstevel@tonic-gate 			/* allocate a scratch buffer */
4347c478bd9Sstevel@tonic-gate 			cbsize = 2*(sizeof (long long)) + 1;
4357c478bd9Sstevel@tonic-gate 			cbuf = MALLOC(cbsize);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 			if (snprintf(cbuf, cbsize, snf, *arg) < 0)
4387c478bd9Sstevel@tonic-gate 				log_message(MSG_ERROR,
43928e0ac9cSToomas Soome 				    "fmt_args: snprintf output error\n");
44028e0ac9cSToomas Soome 			while ((cbuf[ndigits] != '\0') &&
44128e0ac9cSToomas Soome 			    (ndigits < cbsize))
4427c478bd9Sstevel@tonic-gate 				ndigits++;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 			/* if truncation is necessary, do it */
4457c478bd9Sstevel@tonic-gate 			if (ndigits > cw) {
4467c478bd9Sstevel@tonic-gate 				cbuf[cw] = 0;
4477c478bd9Sstevel@tonic-gate 				if (format == 's') {
4487c478bd9Sstevel@tonic-gate 					char *str;
4497c478bd9Sstevel@tonic-gate 					str = (char *)*arg;
4507c478bd9Sstevel@tonic-gate 					str[cw] = 0;
4517c478bd9Sstevel@tonic-gate 				} else
45228e0ac9cSToomas Soome 					*arg = strtol(cbuf, (char **)NULL, cnv);
4537c478bd9Sstevel@tonic-gate 			}
4547c478bd9Sstevel@tonic-gate 			free(cbuf);
4557c478bd9Sstevel@tonic-gate 		}
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	} else {	/* process long formats */
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 		*llarg = POP(DS);
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 		/* check if a column width was specified */
4627c478bd9Sstevel@tonic-gate 		if (cw) {
4637c478bd9Sstevel@tonic-gate 			/* allocate a scratch buffer */
4647c478bd9Sstevel@tonic-gate 			cbsize = 2*(sizeof (long long)) + 1;
4657c478bd9Sstevel@tonic-gate 			cbuf = MALLOC(cbsize);
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 			switch (format) {
4687c478bd9Sstevel@tonic-gate 			case 'p':
4697c478bd9Sstevel@tonic-gate 				cnv = 16;
4707c478bd9Sstevel@tonic-gate 				if (snprintf(cbuf, cbsize, "%p", *llarg) < 0)
4717c478bd9Sstevel@tonic-gate 					log_message(MSG_ERROR,
47228e0ac9cSToomas Soome 					    "fmt_args: snprintf error\n");
4737c478bd9Sstevel@tonic-gate 				break;
4747c478bd9Sstevel@tonic-gate 			case 'x':
4757c478bd9Sstevel@tonic-gate 				cnv = 16;
4767c478bd9Sstevel@tonic-gate 				if (snprintf(cbuf, cbsize, "%lx", *llarg) < 0)
4777c478bd9Sstevel@tonic-gate 					log_message(MSG_ERROR,
4787c478bd9Sstevel@tonic-gate 					    "fmt_args: snprintf error\n");
4797c478bd9Sstevel@tonic-gate 				break;
4807c478bd9Sstevel@tonic-gate 			case 'd':
4817c478bd9Sstevel@tonic-gate 				if (snprintf(cbuf, cbsize, "%ld", *llarg) < 0)
4827c478bd9Sstevel@tonic-gate 					log_message(MSG_ERROR,
48328e0ac9cSToomas Soome 					    "fmt_args: snprintf error\n");
4847c478bd9Sstevel@tonic-gate 				break;
4857c478bd9Sstevel@tonic-gate 			default:
4867c478bd9Sstevel@tonic-gate 				log_message(MSG_ERROR,
4877c478bd9Sstevel@tonic-gate 				    "invalid long format type! (l%s)\n",
48828e0ac9cSToomas Soome 				    &format);
4897c478bd9Sstevel@tonic-gate 				free(cbuf);
4907c478bd9Sstevel@tonic-gate 				return;
4917c478bd9Sstevel@tonic-gate 			}
49228e0ac9cSToomas Soome 			while ((cbuf[ndigits] != '\0') &&
49328e0ac9cSToomas Soome 			    (ndigits < cbsize)) {
4947c478bd9Sstevel@tonic-gate 				ndigits++;
4957c478bd9Sstevel@tonic-gate 			}
4967c478bd9Sstevel@tonic-gate 			/* if truncation is necessary, do it */
4977c478bd9Sstevel@tonic-gate 			if (ndigits > cw) {
4987c478bd9Sstevel@tonic-gate 				cbuf[cw] = 0;
4997c478bd9Sstevel@tonic-gate 				*llarg = strtoll(cbuf, (char **)NULL, cnv);
5007c478bd9Sstevel@tonic-gate 			}
5017c478bd9Sstevel@tonic-gate 			free(cbuf);
5027c478bd9Sstevel@tonic-gate 		}
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate /*
5077c478bd9Sstevel@tonic-gate  *	fmt_str()
5087c478bd9Sstevel@tonic-gate  *
5097c478bd9Sstevel@tonic-gate  * Extracts text from caller's input buffer, processes explicit
5107c478bd9Sstevel@tonic-gate  * formatting as necessary, and outputs formatted text to caller's
5117c478bd9Sstevel@tonic-gate  * receptacle.
5127c478bd9Sstevel@tonic-gate  *
5137c478bd9Sstevel@tonic-gate  *	env  - pointer to caller's fcode environment
5147c478bd9Sstevel@tonic-gate  *	fmt  - pointer to caller's input buffr
5157c478bd9Sstevel@tonic-gate  *	fmtbuf - ponter to caller's receptacle buffer
5167c478bd9Sstevel@tonic-gate  *	bsize - size of caller's fmtbuf buffer
5177c478bd9Sstevel@tonic-gate  *
5187c478bd9Sstevel@tonic-gate  * This function performs an initial test to determine if caller's
5197c478bd9Sstevel@tonic-gate  * input buffer contains formatting(specified by presence of "%")
5207c478bd9Sstevel@tonic-gate  * in the buffer.  If so, validfmt() function is called to verify
5217c478bd9Sstevel@tonic-gate  * the formatting, after which the buffer is processed according
5227c478bd9Sstevel@tonic-gate  * to the field width specified by validfmt() output.  Special
5237c478bd9Sstevel@tonic-gate  * processing is required when caller's buffer contains a double
5247c478bd9Sstevel@tonic-gate  * "%" ("%%"), in which case the second "%" is accepted as normal
5257c478bd9Sstevel@tonic-gate  * text.
5267c478bd9Sstevel@tonic-gate  */
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate static void
fmt_str(fcode_env_t * env,char * fmt,char * fmtbuf,int bsize)5297c478bd9Sstevel@tonic-gate fmt_str(fcode_env_t *env, char *fmt, char *fmtbuf, int bsize)
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate 	char	tbuf[CMN_MSG_SIZE];
5327c478bd9Sstevel@tonic-gate 	char	*fmptr, *pct;
5337c478bd9Sstevel@tonic-gate 	int	l, cw, fw, bytes;
5347c478bd9Sstevel@tonic-gate 	long	arg;
5357c478bd9Sstevel@tonic-gate 	long long llarg;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	*fmtbuf = 0;
5387c478bd9Sstevel@tonic-gate 	if ((pct = strchr(fmt, '%')) != 0) {
5397c478bd9Sstevel@tonic-gate 		cmn_fmt_t	cfstr;
5407c478bd9Sstevel@tonic-gate 		int		vferr;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 		l = strlen(pct++);
5437c478bd9Sstevel@tonic-gate 		vferr = validfmt(pct, &cfstr);
5447c478bd9Sstevel@tonic-gate 		if (!vferr) {
5457c478bd9Sstevel@tonic-gate 			fw = cfstr.fwidth;
5467c478bd9Sstevel@tonic-gate 			cw = cfstr.cwidth;
5477c478bd9Sstevel@tonic-gate 			fmptr = &cfstr.format;
5487c478bd9Sstevel@tonic-gate 		} else {
5497c478bd9Sstevel@tonic-gate 			if (vferr < 0) {
5507c478bd9Sstevel@tonic-gate 			log_message(MSG_ERROR,
5517c478bd9Sstevel@tonic-gate 			    "fmt_str: NULL ptr supplied to validfmt()\n");
5527c478bd9Sstevel@tonic-gate 			return;
5537c478bd9Sstevel@tonic-gate 			}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 			bytes = pct - fmt;
556*09e6639bSToomas Soome 			(void) strncpy(tbuf, fmt, bytes);
557*09e6639bSToomas Soome 			(void) strncpy(tbuf+bytes, "%", 1);
558*09e6639bSToomas Soome 			(void) strncpy(tbuf+bytes+1, fmt+bytes, 1);
5597c478bd9Sstevel@tonic-gate 			bytes += 2;
5607c478bd9Sstevel@tonic-gate 			tbuf[bytes] = 0;
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 			log_message(MSG_ERROR,
56328e0ac9cSToomas Soome 			    "fmt_str: invalid format type! (%s)\n",
56428e0ac9cSToomas Soome 			    tbuf+bytes-3);
5657c478bd9Sstevel@tonic-gate 
566*09e6639bSToomas Soome 			(void) strncpy(fmtbuf, tbuf, bsize);
5677c478bd9Sstevel@tonic-gate 			return;
5687c478bd9Sstevel@tonic-gate 		}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 		if (fw > 0) {	/* process normal (not long) formats */
5717c478bd9Sstevel@tonic-gate 			bytes = pct - fmt + fw;
572*09e6639bSToomas Soome 			(void) strncpy(tbuf, fmt, bytes);
5737c478bd9Sstevel@tonic-gate 			tbuf[bytes] = 0;
5747c478bd9Sstevel@tonic-gate 		} else {
5757c478bd9Sstevel@tonic-gate 			/* if here, fw must be a long format */
5767c478bd9Sstevel@tonic-gate 			if (*fmptr == 'p') {
5777c478bd9Sstevel@tonic-gate 				bytes = pct - fmt - fw;
578*09e6639bSToomas Soome 				(void) strncpy(tbuf, fmt, bytes);
5797c478bd9Sstevel@tonic-gate 				tbuf[bytes] = 0;
5807c478bd9Sstevel@tonic-gate 			} else {
5817c478bd9Sstevel@tonic-gate 				bytes = pct - fmt - fw - 2;
582*09e6639bSToomas Soome 				(void) strncpy(tbuf, fmt, bytes);
5837c478bd9Sstevel@tonic-gate 				tbuf[bytes] = 'l';
584*09e6639bSToomas Soome 				(void) strncpy(tbuf+bytes+1, fmt+bytes, 2);
5857c478bd9Sstevel@tonic-gate 				tbuf[bytes+1+2] = 0;
5867c478bd9Sstevel@tonic-gate 			}
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 		/* if more input buffer to process, recurse */
5907c478bd9Sstevel@tonic-gate 		if ((l - abs(fw)) != 0) {
59128e0ac9cSToomas Soome 			fmt_str(env, pct+abs(fw), (tbuf + strlen(tbuf)),
59228e0ac9cSToomas Soome 			    CMN_MSG_SIZE - strlen(tbuf));
5937c478bd9Sstevel@tonic-gate 		}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 		/* call to extract args for snprintf() calls below */
5967c478bd9Sstevel@tonic-gate 		fmt_args(env, cw, fw, *fmptr, &arg, &llarg);
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 		if (fw > 0) {	/* process normal (not long) formats */
5997c478bd9Sstevel@tonic-gate 			switch (*fmptr) {
6007c478bd9Sstevel@tonic-gate 			case 'd':
6017c478bd9Sstevel@tonic-gate 			case 'x':
6027c478bd9Sstevel@tonic-gate 			case 'c':
6037c478bd9Sstevel@tonic-gate 			case 's':
6047c478bd9Sstevel@tonic-gate 			case 'p':
6057c478bd9Sstevel@tonic-gate 				(void) snprintf(fmtbuf, bsize, tbuf, arg);
6067c478bd9Sstevel@tonic-gate 				break;
6077c478bd9Sstevel@tonic-gate 			case '%':
6087c478bd9Sstevel@tonic-gate 				(void) snprintf(fmtbuf, bsize, tbuf);
6097c478bd9Sstevel@tonic-gate 				break;
6107c478bd9Sstevel@tonic-gate 			default:
6117c478bd9Sstevel@tonic-gate 				log_message(MSG_ERROR,
6127c478bd9Sstevel@tonic-gate 				    "fmt_str: invalid format (%s)\n",
61328e0ac9cSToomas Soome 				    fmptr);
6147c478bd9Sstevel@tonic-gate 				return;
6157c478bd9Sstevel@tonic-gate 			}
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 		} else	/* process long formats */
6187c478bd9Sstevel@tonic-gate 			(void) snprintf(fmtbuf, bsize, tbuf, llarg);
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	} else
621*09e6639bSToomas Soome 		(void) strncpy(fmtbuf, fmt, bsize);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate /*
6257c478bd9Sstevel@tonic-gate  *	fc_cmn_append()
6267c478bd9Sstevel@tonic-gate  *
6277c478bd9Sstevel@tonic-gate  * Pops data stack to obtain message text, and calls fmt_str()
6287c478bd9Sstevel@tonic-gate  * function to perform any message formatting necessary.
6297c478bd9Sstevel@tonic-gate  *
6307c478bd9Sstevel@tonic-gate  * This function is called from fc_cmn_end() or directly in
6317c478bd9Sstevel@tonic-gate  * processing a cmn-append token.  Since a pre-existing message
6327c478bd9Sstevel@tonic-gate  * context is assumed, initial checking is performed to verify
6337c478bd9Sstevel@tonic-gate  * its existence.
6347c478bd9Sstevel@tonic-gate  */
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate void
fc_cmn_append(fcode_env_t * env)6377c478bd9Sstevel@tonic-gate fc_cmn_append(fcode_env_t *env)
6387c478bd9Sstevel@tonic-gate {
6397c478bd9Sstevel@tonic-gate 	int len;
6407c478bd9Sstevel@tonic-gate 	char *str;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	if (root == NULL) {
6437c478bd9Sstevel@tonic-gate 		log_message(MSG_ERROR,
64428e0ac9cSToomas Soome 		    "fc_cmn_append: no message context for append\n");
6457c478bd9Sstevel@tonic-gate 		return;
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	len = POP(DS);
6497c478bd9Sstevel@tonic-gate 	str = (char *)POP(DS);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	if ((root->len + len) < CMN_MSG_SIZE) {
6527c478bd9Sstevel@tonic-gate 		fmt_str(env, str, root->buf+root->len, CMN_MSG_SIZE -
65328e0ac9cSToomas Soome 		    root->len);
6547c478bd9Sstevel@tonic-gate 		root->len += len;
6557c478bd9Sstevel@tonic-gate 	} else
6567c478bd9Sstevel@tonic-gate 		log_message(MSG_ERROR,
65728e0ac9cSToomas Soome 		    "fc_cmn_append: append exceeds max msg size\n");
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate /*
6617c478bd9Sstevel@tonic-gate  *	fc_cmn_end()
6627c478bd9Sstevel@tonic-gate  *
6637c478bd9Sstevel@tonic-gate  * Process ]cmn-end token to log the message initiated by a preceeding
6647c478bd9Sstevel@tonic-gate  * fc_cmn_start() call.
6657c478bd9Sstevel@tonic-gate  *
6667c478bd9Sstevel@tonic-gate  * Since nested cmn-xxx[ calls are supported, a test is made to determine
6677c478bd9Sstevel@tonic-gate  * if this is the final cmn-end of a nested sequence.  If so, or if
6687c478bd9Sstevel@tonic-gate  * there was no nesting, log_message() is called with the appropriate
6697c478bd9Sstevel@tonic-gate  * text buffer.  Otherwise, the root variable is adjusted to point to
6707c478bd9Sstevel@tonic-gate  * the preceeding message in the sequence and links in the list are
6717c478bd9Sstevel@tonic-gate  * updated. No logging is performed until the final ]cmn-end of the
6727c478bd9Sstevel@tonic-gate  * sequence is processed; then, messages are logged in FIFO order.
6737c478bd9Sstevel@tonic-gate  */
6747c478bd9Sstevel@tonic-gate void
fc_cmn_end(fcode_env_t * env)6757c478bd9Sstevel@tonic-gate fc_cmn_end(fcode_env_t *env)
6767c478bd9Sstevel@tonic-gate {
6777c478bd9Sstevel@tonic-gate 	cmn_msg_t *old;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	if (root == 0) {
6807c478bd9Sstevel@tonic-gate 		log_message(MSG_ERROR, "]cmn-end call w/o buffer\n");
6817c478bd9Sstevel@tonic-gate 		return;
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	fc_cmn_append(env);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	if (root->prev == 0) {
6877c478bd9Sstevel@tonic-gate 		cmn_msg_t *next;
6887c478bd9Sstevel@tonic-gate 		do {
6897c478bd9Sstevel@tonic-gate 			log_message(root->level, "%s\n", root->buf);
6907c478bd9Sstevel@tonic-gate 			next  = root->next;
6917c478bd9Sstevel@tonic-gate 			free(root);
6927c478bd9Sstevel@tonic-gate 			root = next;
6937c478bd9Sstevel@tonic-gate 		} while (root);
6947c478bd9Sstevel@tonic-gate 	} else {
6957c478bd9Sstevel@tonic-gate 		old = root->prev;
6967c478bd9Sstevel@tonic-gate 		old->next = root;
6977c478bd9Sstevel@tonic-gate 		root = old;
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate  *	fc_cmn_start()
7037c478bd9Sstevel@tonic-gate  *
7047c478bd9Sstevel@tonic-gate  * Generic function to begin a common message.
7057c478bd9Sstevel@tonic-gate  *
7067c478bd9Sstevel@tonic-gate  * Allocates a new cmn_msg_t to associate with the message, and sets
7077c478bd9Sstevel@tonic-gate  * up initial text as specified by callers' inputs:
7087c478bd9Sstevel@tonic-gate  *
7097c478bd9Sstevel@tonic-gate  *	env  - pointer to caller's fcode environment
7107c478bd9Sstevel@tonic-gate  *	head - pointer to initial text portion of the message
7117c478bd9Sstevel@tonic-gate  *	path - flag to indicate if a device path is to be generated
7127c478bd9Sstevel@tonic-gate  */
7137c478bd9Sstevel@tonic-gate static void
fc_cmn_start(fcode_env_t * env,char * head,int path)7147c478bd9Sstevel@tonic-gate fc_cmn_start(fcode_env_t *env, char *head, int path)
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate 	cmn_msg_t *new;
7177c478bd9Sstevel@tonic-gate 	char		*dpath;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	new = MALLOC(sizeof (cmn_msg_t));
7207c478bd9Sstevel@tonic-gate 	new->prev = root;
7217c478bd9Sstevel@tonic-gate 	if (root != 0)
7227c478bd9Sstevel@tonic-gate 		root->next = new;
723*09e6639bSToomas Soome 	(void) strcpy(new->buf, head);
7247c478bd9Sstevel@tonic-gate 	new->len = strlen(head);
7257c478bd9Sstevel@tonic-gate 	if (path && env->current_device) {
7267c478bd9Sstevel@tonic-gate 		dpath = get_path(env, env->current_device);
727*09e6639bSToomas Soome 		(void) strcpy(new->buf+new->len, dpath);
7287c478bd9Sstevel@tonic-gate 		new->len += strlen(dpath);
729*09e6639bSToomas Soome 		(void) strncpy(new->buf+new->len++, ": ", 2);
7307c478bd9Sstevel@tonic-gate 		++new->len;
7317c478bd9Sstevel@tonic-gate 		free(dpath);
7327c478bd9Sstevel@tonic-gate 	}
7337c478bd9Sstevel@tonic-gate 	new->level = cmn_msg_level;
7347c478bd9Sstevel@tonic-gate 	new->next = NULL;
7357c478bd9Sstevel@tonic-gate 	root = new;
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate /*
7397c478bd9Sstevel@tonic-gate  *	fc_cmn_type()
7407c478bd9Sstevel@tonic-gate  *
7417c478bd9Sstevel@tonic-gate  * Process cmn-type[ token.
7427c478bd9Sstevel@tonic-gate  *
7437c478bd9Sstevel@tonic-gate  * Invokes fc_cmn_start() to create a message containing blank
7447c478bd9Sstevel@tonic-gate  * header and no device path information.
7457c478bd9Sstevel@tonic-gate  */
7467c478bd9Sstevel@tonic-gate void
fc_cmn_type(fcode_env_t * env)7477c478bd9Sstevel@tonic-gate fc_cmn_type(fcode_env_t *env)
7487c478bd9Sstevel@tonic-gate {
7497c478bd9Sstevel@tonic-gate 	cmn_msg_level = MSG_INFO;
7507c478bd9Sstevel@tonic-gate 	fc_cmn_start(env, "", 0);
7517c478bd9Sstevel@tonic-gate }
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate /*
7547c478bd9Sstevel@tonic-gate  *	fc_cmn_msg()
7557c478bd9Sstevel@tonic-gate  *
7567c478bd9Sstevel@tonic-gate  * Process cmn-msg[ token.
7577c478bd9Sstevel@tonic-gate  *
7587c478bd9Sstevel@tonic-gate  * Invokes fc_cmn_start() to create a message containing blank
7597c478bd9Sstevel@tonic-gate  * header but specifying device path information.
7607c478bd9Sstevel@tonic-gate  */
7617c478bd9Sstevel@tonic-gate void
fc_cmn_msg(fcode_env_t * env)7627c478bd9Sstevel@tonic-gate fc_cmn_msg(fcode_env_t *env)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	cmn_msg_level = MSG_INFO;
7667c478bd9Sstevel@tonic-gate 	fc_cmn_start(env, "", 1);
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate /*
7707c478bd9Sstevel@tonic-gate  *	fc_cmn_note()
7717c478bd9Sstevel@tonic-gate  *
7727c478bd9Sstevel@tonic-gate  * Process cmn-note[ token.
7737c478bd9Sstevel@tonic-gate  *
7747c478bd9Sstevel@tonic-gate  * Invokes fc_cmn_start() to create a message with NOTICE stamping in
7757c478bd9Sstevel@tonic-gate  * the header and specification of device path information.
7767c478bd9Sstevel@tonic-gate  */
7777c478bd9Sstevel@tonic-gate void
fc_cmn_note(fcode_env_t * env)7787c478bd9Sstevel@tonic-gate fc_cmn_note(fcode_env_t *env)
7797c478bd9Sstevel@tonic-gate {
7807c478bd9Sstevel@tonic-gate 	cmn_msg_level = MSG_NOTE;
7817c478bd9Sstevel@tonic-gate 	fc_cmn_start(env, "NOTICE: ", 1);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate /*
7857c478bd9Sstevel@tonic-gate  *	fc_cmn_warn()
7867c478bd9Sstevel@tonic-gate  *
7877c478bd9Sstevel@tonic-gate  * Process cmn-warn[ token.
7887c478bd9Sstevel@tonic-gate  *
7897c478bd9Sstevel@tonic-gate  * Invokes fc_cmn_start() to create a message with WARNING stamping in
7907c478bd9Sstevel@tonic-gate  * the header and specification of device path information.
7917c478bd9Sstevel@tonic-gate  */
7927c478bd9Sstevel@tonic-gate void
fc_cmn_warn(fcode_env_t * env)7937c478bd9Sstevel@tonic-gate fc_cmn_warn(fcode_env_t *env)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate 	cmn_msg_level = MSG_WARN;
7967c478bd9Sstevel@tonic-gate 	fc_cmn_start(env, "WARNING: ", 1);
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate /*
8007c478bd9Sstevel@tonic-gate  *	fc_cmn_error()
8017c478bd9Sstevel@tonic-gate  *
8027c478bd9Sstevel@tonic-gate  * Process cmn-error[ token.
8037c478bd9Sstevel@tonic-gate  *
8047c478bd9Sstevel@tonic-gate  * Invokes fc_cmn_start() to create a message with ERROR stamping in
8057c478bd9Sstevel@tonic-gate  * the header and specification of device path information.
8067c478bd9Sstevel@tonic-gate  */
8077c478bd9Sstevel@tonic-gate void
fc_cmn_error(fcode_env_t * env)8087c478bd9Sstevel@tonic-gate fc_cmn_error(fcode_env_t *env)
8097c478bd9Sstevel@tonic-gate {
8107c478bd9Sstevel@tonic-gate 	cmn_msg_level = MSG_ERROR;
8117c478bd9Sstevel@tonic-gate 	fc_cmn_start(env, "ERROR: ", 1);
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate /*
8157c478bd9Sstevel@tonic-gate  *	fc_cmn_fatal()
8167c478bd9Sstevel@tonic-gate  *
8177c478bd9Sstevel@tonic-gate  * Process cmn-fatal[ token.
8187c478bd9Sstevel@tonic-gate  *
8197c478bd9Sstevel@tonic-gate  * Invokes fc_cmn_start() to create a message with FATAL stamping in
8207c478bd9Sstevel@tonic-gate  * the header and specification of device path information.
8217c478bd9Sstevel@tonic-gate  */
8227c478bd9Sstevel@tonic-gate void
fc_cmn_fatal(fcode_env_t * env)8237c478bd9Sstevel@tonic-gate fc_cmn_fatal(fcode_env_t *env)
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate 	cmn_msg_level = MSG_FATAL;
8267c478bd9Sstevel@tonic-gate 	fc_cmn_start(env, "FATAL: ", 1);
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate #pragma init(_init)
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate static void
_init(void)8327c478bd9Sstevel@tonic-gate _init(void)
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate 	fcode_env_t *env = initial_env;
8357c478bd9Sstevel@tonic-gate 	ASSERT(env);
8367c478bd9Sstevel@tonic-gate 	NOTICE;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	ANSI(0x088, 0,		"span",			span);
8397c478bd9Sstevel@tonic-gate 	ANSI(0x08a, 0,		"expect",		expect);
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	ANSI(0x08d, 0,		"key?",			keyquestion);
8427c478bd9Sstevel@tonic-gate 	ANSI(0x08e, 0,		"key",			key);
8437c478bd9Sstevel@tonic-gate 	ANSI(0x08f, 0,		"emit",			emit);
8447c478bd9Sstevel@tonic-gate 	ANSI(0x090, 0,		"type",			type);
8457c478bd9Sstevel@tonic-gate 	ANSI(0x091, 0,		"(cr",			paren_cr);
8467c478bd9Sstevel@tonic-gate 	ANSI(0x092, 0,		"cr",			fc_crlf);
8477c478bd9Sstevel@tonic-gate 	ANSI(0x093, 0,		"#out",			fc_num_out);
8487c478bd9Sstevel@tonic-gate 	ANSI(0x094, 0,		"#line",		fc_num_line);
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	FCODE(0x125, 0,		"get-msecs",		do_get_msecs);
8517c478bd9Sstevel@tonic-gate 	FCODE(0x126, 0,		"ms",			do_ms);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	FORTH(0,		"verbose-emit",		do_verbose_emit);
8547c478bd9Sstevel@tonic-gate 	FCODE(0x7e9, 0,		"cmn-fatal[",		fc_cmn_fatal);
8557c478bd9Sstevel@tonic-gate 	FCODE(0x7ea, 0,		"cmn-error[",		fc_cmn_error);
8567c478bd9Sstevel@tonic-gate 	FCODE(0x7eb, 0,		"cmn-warn[",		fc_cmn_warn);
8577c478bd9Sstevel@tonic-gate 	FCODE(0x7ec, 0,		"cmn-note[",		fc_cmn_note);
8587c478bd9Sstevel@tonic-gate 	FCODE(0x7ed, 0,		"cmn-type[",		fc_cmn_type);
8597c478bd9Sstevel@tonic-gate 	FCODE(0x7ee, 0,		"cmn-append",		fc_cmn_append);
8607c478bd9Sstevel@tonic-gate 	FCODE(0x7ef, 0,		"]cmn-end",		fc_cmn_end);
8617c478bd9Sstevel@tonic-gate 	FCODE(0x7f0, 0,		"cmn-msg[",		fc_cmn_msg);
8627c478bd9Sstevel@tonic-gate }
863