OpenSolaris_b135/lib/libeti/form/common/chg_data.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*	Copyright (c) 1988 AT&T	*/
/*	  All Rights Reserved  	*/


/*
 *      Copyright (c) 1997, by Sun Microsystems, Inc.
 *      All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*LINTLIBRARY*/

#include <sys/types.h>
#include <stdlib.h>
#include "utility.h"

#define	AT_BOTTOM(f)	(Y(f) == Ymax(f) - 1)		/* last line	*/
#define	AT_END(f)	(Y(f) == Ymax(f) - 1 && X(f) == Xmax(f) - 1)
							/* last char */
#define	AT_BEGINNING(f)	(Y(f) == 0 && X(f) == 0)	/* first char	*/

static int
room_for_line(FORM *f)
{
	char *v;

	_sync_buffer(f);
	v = LineBuf(C(f), Ymax(f) - 1);
	return (v == _data_end(v, Xmax(f)));	/* check for empty line */
}

static int
room_for_char(FORM *f)
{
	WINDOW * w = W(f);
	int c;

	(void) wmove(w, Y(f), Xmax(f) - 1);
	c = (int)(winch(w) & A_CHARTEXT);
	(void) wmove(w, Y(f), X(f));
	return (c == Pad(C(f)));	/* check for empty char */
}

static int
extra_padding(char *str, int nstr)		/* used for word wrapping */
{
	int c = *(str + nstr - 1);

	if (c == '"' || c == '\'')
		c = *(str + nstr - 2);

	return ((c == '.' || c == '?' || c == '!' || c == ':') ? 2 : 1);

}

BOOLEAN
_grow_field(FIELD *c, int chunks)
{
	/* This function handles the growth of dymanically growable fields */
	/* Returns TRUE if successful, FALSE otherwise	*/

	FORM		*f = c->form;
	WINDOW		*w = W(f);
	BOOLEAN		current = Status(f, POSTED) && c == C(f);
	char		*old_buf;
	char		*new_buf;
	char		*save;
	int		old_len = BufSize(c);
	int		grow;
	int		lcv;
	int		max = c->maxgrow;
	int		i;

	if (current && Status(f, WIN_CHG)) {
		_win_to_buf(w, c);
		Clr(f, WIN_CHG);
		Set(f, BUF_CHG);
	}

	if (OneRow(c)) {
		grow = chunks * c->cols;

		if (max)
			grow = MIN(max - c->dcols, grow);

		c->dcols += grow;

		if (c->dcols == max)
			Clr(c, GROWABLE);
	} else {
		grow = chunks * (c->rows + c->nrow);

		if (max)
			grow = MIN(max - c->drows, grow);

		c->drows += grow;
		grow *= c->cols;

		if (c->drows == max)
			Clr(c, GROWABLE);
	}

	save = old_buf = Buf(c);
	new_buf = Buf(c) = malloc(TotalBuf(c));

	if (!new_buf)
		return (FALSE);

	lcv = c->nbuf + 1;

	for (i = 0; i < lcv; i++) {
		(void) memcpy(new_buf, old_buf, old_len);
		(void) memset(new_buf + old_len, ' ', grow);
		old_buf += old_len + 1;
		new_buf += old_len + grow;
		*new_buf++ = '\0';
	}

	free(save);	/* delete old buffer */

	if (current) {
		(void) delwin(w);
		W(f) = w = newwin(c->drows, c->dcols, 0, 0);

		if (!w)
			return (FALSE);

		wbkgdset(w, Pad(c) | Back(c));
		(void) wattrset(w, Fore(c));
		(void) werase(w);
		_buf_to_win(c, w);
		(void) untouchwin(w);
		(void) wmove(w, Y(f), X(f));
	}

	if (c->link != c) {
		FIELD	*p = c->link;

		while (p != c) {
			Buf(p) = Buf(c);
			p->drows = c->drows;
			p->dcols = c->dcols;
			/* _sync_field(p) */
			p = p->link;
		}
	}

	return (TRUE);
}

static int
insert_str(FORM *f, int y, int off, int nstr)	/* used for word wrapping */
{
	WINDOW		*w	= W(f);
	FIELD		*c	= C(f);
	char		*vbeg	= LineBuf(c, y);
	char		*v	= _data_end(vbeg, Xmax(f));
	int		x	= (int)(v - vbeg);
	int		n	= Xmax(f) - x;
	int		pad	= extra_padding(Buf(c) + off, nstr);
	int		siz	= nstr + 1 + pad;
	int		ret 	= E_REQUEST_DENIED;

	if (n >= siz) {	/* check for fit on this line */
		(void) wmove(w, y, 0);
		(void) winsnstr(w, Buf(c) + off, nstr);
		(void) wmove(w, y, nstr);
		(void) winsnstr(w, "  ", pad);
	} else {		/* wrap */
		if (y == Ymax(f) - 1 && Status(c, GROWABLE)) {
			if (!_grow_field(c, 1))
				return (E_SYSTEM_ERROR);

			vbeg = LineBuf(c, y);	/* grow changes buffer */
			w = W(f);		/* grow changes window */
		}

		v = _data_beg(vbeg + Xmax(f) - siz, siz);
		v = _whsp_end(vbeg, (int)(v - vbeg));
		x = (int)(v - vbeg);
		n = Xmax(f) - x - n;

		if (y < Ymax(f) - 1 && (ret =
		    insert_str(f, y+1, (int)(v - Buf(c)), n)) == E_OK) {
			(void) wmove(w, y, x);
			(void) wclrtoeol(w);
			(void) wmove(w, y, 0);
			(void) winsnstr(w, Buf(c) + off, nstr);
			(void) wmove(w, y, nstr);
			(void) winsnstr(w, "  ", pad);
		} else
			return (ret);	/* no room for wrap */
	}
	return (E_OK);
}

static int
wrap_ok(FORM *f)		/* used for word wrapping */
{
/*
 * when this routine is called a char has already been added/inserted
 * on the screen at Y(f), X(f).  this routine checks to see if the current
 * line needs wrapping and if so attempts the wrap.  if unsuccessful
 * it deletes the char at Y(f), X(f) and returns FALSE.
 */
	FIELD		*c = C(f);
	BOOLEAN		at_bottom = AT_BOTTOM(f);
	int		ret = E_REQUEST_DENIED;

	if (Opt(c, O_WRAP) && !OneRow(c) && !room_for_char(f) &&
	    (!at_bottom || Status(c, GROWABLE))) {
		WINDOW *w;
		char *vbeg;
		char *v;
		int x, n;

		if (at_bottom && !_grow_field(c, 1))
			return (E_SYSTEM_ERROR);

		vbeg = LineBuf(c, Y(f));
		w = W(f);

		_win_to_buf(w, c);	/* sync buffer without changing flags */

		v = _whsp_end(vbeg, Xmax(f));
		x = (int)(v - vbeg);
		n = Xmax(f) - x;

		if (x && (ret = insert_str(f, Y(f)+1, (int)(v - Buf(c)), n)) ==
		    E_OK) {
			w = W(f);	/* window may change in insert_str */
			(void) wmove(w, Y(f), x);
			(void) wclrtoeol(w);

			if (X(f) >= x) {
				++Y(f);
				X(f) = X(f) - x;
			}
		} else {	/* error condition */
			if (ret == E_SYSTEM_ERROR)
				return (E_SYSTEM_ERROR);

			(void) wmove(w, Y(f), X(f));
			(void) wdelch(w);	/* delete the char */
			_win_to_buf(w, c);	/* restore buffer  */
			return (E_REQUEST_DENIED);
		}
	}
	return (E_OK);
}

int
_new_line(FORM *f)
{
/*
 *		overloaded operation
 *
 *	if at beginning of field
 *		move to next field
 *
 *	else if in OVERLAY mode
 *		if on last line of field
 *			clear to eol and move to next field
 *		else
 *			clear to eol and move to beginning of next line
 *
 *	else if in INSERT mode
 *		if on last line of field
 *			move to next field
 *		else
 *			move text from cursor to eol to new line
 */
	BOOLEAN		at_bottom = AT_BOTTOM(f);
	FIELD *		c = C(f);

	if (Opt(f, O_NL_OVERLOAD) && AT_BEGINNING(f))
		return (_field_navigation(_next_field, f));

	if (!Opt(c, O_EDIT))
		return (E_REQUEST_DENIED);

	if (Status(f, OVERLAY)) {		/* OVERLAY mode	*/
		if (at_bottom && (!Status(c, GROWABLE) || OneRow(c))) {
			if (Opt(f, O_NL_OVERLOAD)) {
				(void) wclrtoeol(W(f));
				Set(f, WIN_CHG);
				return (_field_navigation(_next_field, f));
			} else
				return (E_REQUEST_DENIED);
		}

		if (at_bottom && !_grow_field(c, 1))
			return (E_SYSTEM_ERROR);

		(void) wclrtoeol(W(f));
		++Y(f); X(f) = 0;
	} else {		/* INSERT mode	*/
		BOOLEAN		room;

		if (at_bottom && (!Status(c, GROWABLE) || OneRow(c))) {
			if (Opt(f, O_NL_OVERLOAD))
				return (_field_navigation(_next_field, f));
			else
				return (E_REQUEST_DENIED);
		}

		room = !at_bottom && room_for_line(f);

		if (room || Status(c, GROWABLE)) {
			WINDOW	*w;
			char *v;
			char *vend;

			if (!room && !_grow_field(c, 1))
				return (E_SYSTEM_ERROR);

			w = W(f);
			v = LineBuf(c, Y(f)) + X(f);
			vend = _data_end(v, Xmax(f) - X(f));

			(void) wclrtoeol(w);
			++Y(f); X(f) = 0;
			(void) wmove(w, Y(f), X(f));
			(void) winsertln(w);
			(void) waddnstr(w, v, (int)(vend - v));
		} else
			return (E_REQUEST_DENIED);
	}
	Set(f, WIN_CHG);
	return (E_OK);
}

/* _ins_char - insert blank char with error on overflow */
int
_ins_char(FORM *f)
{
	FIELD	*c = C(f);
	BOOLEAN	room = room_for_char(f);

	if (CheckChar(c, ' ') && (room || (OneRow(c) &&
	    Status(c, GROWABLE)))) {
		if (!room && !_grow_field(c, 1))
			return (E_SYSTEM_ERROR);

		(void) winsch(W(f), ' ');

		return (wrap_ok(f));
	}
	return (E_REQUEST_DENIED);
}

/* _ins_line -  insert blank line with error on overflow */
int
_ins_line(FORM *f)
{
	BOOLEAN		room = !AT_BOTTOM(f) && room_for_line(f);
	FIELD		*c = C(f);

	if (CheckChar(c, ' ') && !OneRow(c) && (room || Status(c, GROWABLE))) {
		if (!room && !_grow_field(c, 1))
			return (E_SYSTEM_ERROR);

		X(f) = 0;
		(void) winsertln(W(f));
		return (E_OK);
	}
	return (E_REQUEST_DENIED);
}

/* _del_char - delete char at cursor */
int
_del_char(FORM *f)
{
	(void) wdelch(W(f));
	return (E_OK);
}

int
_del_prev(FORM *f)
{
/*
 *		overloaded operation
 *
 *	if at beginning of field
 *		move to previous field
 *
 *	else if in OVERLAY mode
 *		if at beginning of line
 *			error
 *		else
 *			delete previous char
 *
 *	else if in INSERT mode
 *		if at beginning of line
 *			if current line can fit on preceding
 *				join current line with preceding line
 *			else
 *				error
 *		else
 *			delete previous char
 */
	WINDOW *	w = W(f);
	FIELD *		c = C(f);

	if (AT_BEGINNING(f)) {
		if (Opt(f, O_BS_OVERLOAD))
			return (_field_navigation(_prev_field, f));
		else
			return (E_REQUEST_DENIED);
	}
	if (!Opt(c, O_EDIT))
		return (E_REQUEST_DENIED);

	if (--X(f) < 0) {
		++X(f);

		if (Status(f, OVERLAY))	/* OVERLAY mode	*/
			return (E_REQUEST_DENIED);
		else {			/* INSERT mode	*/
			char *p = LineBuf(c, Y(f) - 1);
			char *v = LineBuf(c, Y(f));
			char *pend;
			char *vend;

			_sync_buffer(f);
			pend = _data_end(p, Xmax(f));
			vend = _data_end(v, Xmax(f));

			if ((vend - v) > (Xmax(f) - (pend - p)))
				return (E_REQUEST_DENIED);
			else {
				(void) wdeleteln(w);
				_adjust_cursor(f, pend);
				(void) wmove(w, Y(f), X(f));
				(void) waddnstr(w, v, (int)(vend - v));
			}
		}
	} else {
		(void) wmove(w, Y(f), X(f));
		(void) wdelch(w);
	}
	Set(f, WIN_CHG);
	return (E_OK);
}

/* _del_line - delete current line */
int
_del_line(FORM *f)
{
	X(f) = 0;
	(void) wdeleteln(W(f));
	return (E_OK);
}

/* _del_word - delete word under cursor plus trailing blanks */
int
_del_word(FORM *f)
{
	FIELD *c = C(f);
	WINDOW *w = W(f);
	char *y = LineBuf(c, Y(f));
	char *t = y + Xmax(f);
	char *v = y + X(f);
	char *x = v;

	_sync_buffer(f);

	if (*v == ' ')
		return (E_REQUEST_DENIED);

	_adjust_cursor(f, _whsp_end(y, X(f)));
	(void) wmove(w, Y(f), X(f));
	(void) wclrtoeol(w);

	v = _whsp_beg(v, (int)(t - v));
	v = _data_beg(v, (int)(t - v));

	if (v != x && *v != ' ')
		(void) waddnstr(w, v, (int)(_data_end(v, (int)(t - v)) - v));

	return (E_OK);
}

/* _clr_eol - clear to end of line */
int
_clr_eol(FORM *f)
{
	(void) wclrtoeol(W(f));
	return (E_OK);
}

/* _clr_eof - clear to end of field */
int
_clr_eof(FORM *f)
{
	(void) wclrtobot(W(f));
	return (E_OK);
}

/* _clr_field - clear entire field */
int
_clr_field(FORM *f)
{
	X(f) = 0; Y(f) = 0;
	(void) werase(W(f));
	return (E_OK);
}

/* _ovl_mode - go into overlay mode */
int
_ovl_mode(FORM *f)
{
	Set(f, OVERLAY);
	return (E_OK);
}

/* _ins_mode - go into insert mode */
int
_ins_mode(FORM *f)
{
	Clr(f, OVERLAY);
	return (E_OK);
}

/* _validation - apply validation function associated with field type */
int
_validation(FORM *f)
{
	return (_validate(f) ? E_OK : E_INVALID_FIELD);
}

/* _next_choice - apply next choice function associated with field type */
int
_next_choice(FORM *f)
{
	_sync_buffer(f);
	return (NextChoice(C(f)) ? E_OK : E_REQUEST_DENIED);
}

/* _prev_choice - apply previous choice function associated with field type */
int
_prev_choice(FORM *f)
{
	_sync_buffer(f);
	return (PrevChoice(C(f)) ? E_OK : E_REQUEST_DENIED);
}

/*
 * _data_entry - enter printable ascii char ch
 * in current field at cursor position
 */
int
_data_entry(FORM *f, int ch)
{
	FIELD *		c = C(f);	/* current field	*/
	WINDOW *	w = W(f);	/* field window		*/
	BOOLEAN		at_end;
	int		ret;

	if (!Opt(c, O_EDIT))
		return (E_REQUEST_DENIED);

	if (AT_BEGINNING(f) && Opt(c, O_BLANK) && ! Status(f, BUF_CHG) &&
	    !Status(f, WIN_CHG))
		(void) werase(w);

	if (Status(f, OVERLAY))	/* OVERLAY mode	*/
		(void) waddch(w, (chtype) ch);
	else {				/* INSERT mode	*/
		BOOLEAN	room = room_for_char(f);

		if (room || (OneRow(c) && Status(c, GROWABLE))) {
			if (!room && !_grow_field(c, 1))
				return (E_SYSTEM_ERROR);

			(void) winsch(w, (chtype) ch);
		} else
			return (E_REQUEST_DENIED);
	}

	if ((ret = wrap_ok(f)) != E_OK)
		return (ret);

	Set(f, WIN_CHG);

	at_end = AT_END(f);

	if (at_end && !Status(c, GROWABLE) && Opt(c, O_AUTOSKIP))
		return (_field_navigation(_next_field, f));

	if (at_end && Status(c, GROWABLE) && !_grow_field(c, 1))
		return (E_SYSTEM_ERROR);

	(void) _next_char(f);
	return (E_OK);
}