/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 *
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"$Header: fmtmsg.c 1.4 90/09/07 $@(#)nlp:lib/oam/fmtmsg.c	1.4"
/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */

#include "stdio.h"
#include "string.h"

#include "oam.h"
#include <euc.h>
#include <getwidth.h>

/*
 * Define the following if you want the ID tags to follow the message.
 * We don't currently because (1) they're obnoxious, and (2) are really
 * meaningless as they stand (in SVR3.2). Also, they change as we add
 * messages (this is a fault of the implementation), and they aren't
 * likely to track into SVR4.0.
 */
/* #define OBNOXIOUS	/* */

static char		*severity_names[MAX_SEVERITY-MIN_SEVERITY+1] = {
	"HALT",
	"ERROR",
	"WARNING",
	"INFO"
};

static char		*TOFIX	= "TO FIX";

static int		wrap(), strcspn_i18n(), chk_i18n_chars();

static eucwidth_t	wp;

/**
 ** fmtmsg()
 **/

int			fmtmsg (
				label,
				classification,
				severity,
				text,
				tag,
				action
			)
	char			*label;
	long			classification;
	int			severity;
	char			*text,
				*tag,
				*action;
{
	int			label_len	= strlen(label),
				tofix_len	= strlen(TOFIX),
				severity_len,
				max_len,
				n,
				nchars,
				have_act;

	char			*severity_name,
				*source;

	getwidth(&wp);

	/*
	 * Adjust codeset 2 and 3's width to include the single shift char. 
	 *
	wp._eucw2++;		
	wp._eucw3++;

/*
 * DON'T MESS WITH THE CONTENT OF STRINGS!
 */
	/*
	 * The requirements don't say to return -1 if the
	 * severity isn't recognized, but we do.
	 */
	if (severity < MIN_SEVERITY || MAX_SEVERITY < severity)
		return (-1);
	else {
		severity_name = severity_names[severity];
		severity_len = strlen(severity_name);
	}

	/*
	 * The requirements don't say to return -1 if the
	 * label isn't structured correctly, but we do.
	 */
	if (!(source = strchr(label, ':')))
		return (-1);
	source++;

	max_len = label_len + severity_len + 2;
	if (max_len < tofix_len)
		max_len = tofix_len;

	have_act = (action && *action);

	if ((n = wrap(label, severity_name, max_len, text, 50, !have_act)) <= 0)
		return (-1);
	else
		nchars = n;

	if (have_act) {
		if (fputc('\n', stderr) == EOF)
			return (-1);
		else
			nchars++;

		if ((n = wrap(TOFIX, "", max_len, action, 40, 1)) <= 0)
			return (-1);
		else
			nchars += n;
	}

#if	defined(OBNOXIOUS)
	n = fprintf(
		stderr,
		"%.*s%s%s\n",
		source - label - 1,
		label,
		source,
		tag
	);
#else
	n = fprintf(stderr, "\n");
#endif
	if (n <= 0)
		return (-1);
	else
		nchars += n;

	fflush (stderr);

	return (nchars);
}

/**
 ** wrap() - PUT OUT "STUFF: string", WRAPPING string AS REQUIRED
 **/
static int		wrap (prefix, suffix, max_len, str, str_brk, tag)
	char			*prefix,
				*suffix;
	int			max_len;
	char			*str;
	int			str_brk,
				tag;
{
	int			len,
				n,
				nchars;

	char			*p;

#if	defined(SMART_WRAP)
	char			*pw;
#endif


	/*
	 * Display the initial stuff followed by a colon.
	 */
	if ((len = strlen(suffix)))
		n = fprintf(
			stderr,
			"%*s: %s: ",
			max_len - len - 2,
			prefix,
			suffix
		);
	else
		n = fprintf(stderr, "%*s: ", max_len, prefix);
	if (n <= 0)
		return (-1);
	nchars = n;

	/*
	 * Loop once for each line of the string to display.
	 */
	for (p = str; *p; ) {

		/*
		 * Display the next "len" bytes of the string, where
		 * "len" is the smallest of:
		 *
		 *	- "str_brk"
		 *	- # bytes before control character
		 *	- # bytes left in string
		 *
#if	defined(SMART_WRAP)
		 * Modify "len" to avoid splitting ``small'' words.
#endif
		 */

		len = strcspn_i18n(p, "\r\n");
		if (len > str_brk) {

			len = str_brk;
#if	defined(SMART_WRAP)
			/*
			 * Don't split ``small'' words or before the
			 * last ``few'' characters of any word.
			 */
# define SMART_SMALL	4
# define SMART_FEW	0
			for (
				pw = p + len - 1;
				pw >= p && *pw != ' ';
				pw--
			)
				;
			if ((strcspn(++pw, " ") <= SMART_SMALL) || 
			    (strcspn(p + len, " ") <= SMART_FEW)) {
				if (pw > p)
					len = pw - p;
			}
#endif
		}

		len = chk_i18n_chars(p, len);

		n = fprintf(stderr, "%.*s", len, p);
		if (n <= 0)
			return (-1);
		nchars += n;

		/*
		 * If we displayed up to a control character,
		 * put out the control character now; otherwise,
		 * put out a newline unless we've put out all
		 * the text.
		 */
		p += len;
		if (*p == '\r' || *p == '\n') {

			if (fputc(*p, stderr) == EOF)
				return (-1);
			else
				nchars++;
			p++;

		} else if (*p) {

			if (fputc('\n', stderr) == EOF)
				return (-1);
			else
				nchars++;

		} else if (tag) {

#if	defined(OBNOXIOUS)
#define LEAVE_ROOM 3
			while (len++ < str_brk - LEAVE_ROOM)
				if (fputc(' ', stderr) == EOF)
					return (-1);
				else
					nchars++;
#endif

		}

		/*
		 * If the loop won't end this time (because we
		 * have more stuff to display) put out leading
		 * blanks to align the next line with the previous
		 * lines.
		 */
		if (*p) {
			for (n = -2; n < max_len; n++)
				if (fputc(' ', stderr) == EOF)
					return (-1);
			nchars += max_len + 2;
		}

	}

	return (nchars);
}


/*
 * chk_i18n_chars - Make sure that multibyte characters are not 
 *		    split in half.
 */
static int
chk_i18n_chars(orig_p, len)
 	char 	*orig_p;
	int	len;
{
	int	done;
 	char 	*p;


	/* 
	 * If no multibyte chars return original length
	 */
	if (!wp._multibyte)
		return(len);

	done = 0;
	p = orig_p;

	while (!done) {
		
		switch(*p) {

			default:
				if (ISASCII(*p)) {
					if (((int)(p - orig_p) + 1) > len)
						done = 1;
					else
						++p;
				}
				else {
					if (((int)(p - orig_p) + wp._eucw1) > len)
						done = 1;
					else
						p += wp._eucw1;
				}
				break;

			case SS2:
				if (((int)(p - orig_p) + wp._eucw2) > len)
					done = 1;
				else
					p += wp._eucw2;

				break;

			case SS3:
				if (((int)(p - orig_p) + wp._eucw3) > len)
					done = 1;
				else
					p += wp._eucw3;

				break;
		}
	}
	return(p - orig_p);
}


/*
 * strcspn_i18n - Get the actual number of colmuns that the string
 *		  will occupy, not the number of bytes (strcspn).
 */
static int
strcspn_i18n(p, str)
 	char 	*p;
	char	*str;
{
	char	*q;
	int	len;

	len = 0;

	while (*p) {
		for (q = str; (*q != '\0') && (*p != *q); ++q)
			;

		if (*q != '\0')
			break;

		switch(*p) {

			default:
				if (ISASCII(*p)) {	/* Code set 0 */
					++p;
					++len;
				}
				else  {			/* Code set 1 */	
					p += wp._eucw1;
					len += wp._scrw1;
				}
				break;

			case SS2:			/* Code set 2 */
				p += wp._eucw2;
				len += wp._scrw2;
				break;

			case SS3:			/* Code set 3 */
				p += wp._eucw3;
				len += wp._scrw3;
				break;
		}
	}
	return len;
}
