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