4.4BSD/usr/src/contrib/nvi/nvi/util.c

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

/*-
 * Copyright (c) 1991, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
static char sccsid[] = "@(#)util.c	8.1 (Berkeley) 6/9/93";
#endif /* not lint */

#include <sys/types.h>
#include <sys/ioctl.h>

#include <ctype.h>
#include <curses.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#include "vi.h"

/*
 * msgq --
 *	Display a message.
 */
void
#ifdef __STDC__
msgq(SCR *sp, enum msgtype mt, const char *fmt, ...)
#else
msgq(sp, mt, fmt, va_alist)
	SCR *sp;
	enum msgtype mt;
        char *fmt;
        va_dcl
#endif
{
        va_list ap;
	int len;
	char msgbuf[1024];

#ifdef __STDC__
        va_start(ap, fmt);
#else
        va_start(ap);
#endif
	/*
	 * It's possible to reenter msg when it allocates space.
	 * We're probably dead anyway, but no reason to drop core.
	 */
	if (F_ISSET(sp, S_MSGREENTER))
		return;
	F_SET(sp, S_MSGREENTER);

	switch (mt) {
	case M_BERR:
		if (!O_ISSET(sp, O_VERBOSE)) {
			F_SET(sp, S_BELLSCHED);
			F_CLR(sp, S_MSGREENTER);
			return;
		}
		mt = M_ERR;
		break;
	case M_ERR:
		break;
	case M_INFO:
		break;
	case M_VINFO:
		if (!O_ISSET(sp, O_VERBOSE)) {
			F_CLR(sp, S_MSGREENTER);
			return;
		}
		mt = M_INFO;
		break;
	default:
		abort();
	}

	/* Length is the min length of the message or the buffer. */
	len = vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
	if (len > sizeof(msgbuf))
		len = sizeof(msgbuf);

	msg_app(NULL, sp, mt == M_ERR ? 1 : 0, msgbuf, len);

	F_CLR(sp, S_MSGREENTER);
}

/*
 * msg_app --
 *	Append a message into the queue.  This can fail, but there's nothing
 *	we can do if it does.
 */
void
msg_app(gp, sp, inv_video, p, len)
	GS *gp;
	SCR *sp;
	int inv_video;
	char *p;
	size_t len;
{
	MSG *mp;
	int new;

	/*
	 * Find an empty structure, or allocate a new one.  Use the
	 * screen structure if possible, otherwise the global one.
	 */
	new = 0;
	if (sp != NULL)
		if (sp->msgp == NULL) {
			if ((sp->msgp = malloc(sizeof(MSG))) == NULL)
				return;
			new = 1;
			mp = sp->msgp;
		} else {
			mp = sp->msgp;
			goto loop;
		}
	else if (gp->msgp == NULL) {
		if ((gp->msgp = malloc(sizeof(MSG))) == NULL)
			return;
		mp = gp->msgp;
		new = 1;
	} else {
		mp = gp->msgp;
loop:		for (;
		    !F_ISSET(mp, M_EMPTY) && mp->next != NULL; mp = mp->next);
		if (!F_ISSET(mp, M_EMPTY)) {
			if ((mp->next = malloc(sizeof(MSG))) == NULL)
				return;
			mp = mp->next;
			new = 1;
		}
	}

	/* Initialize new structures. */
	if (new)
		memset(mp, 0, sizeof(MSG));

	/* Store the message. */
	if (len > mp->blen && binc(sp, &mp->mbuf, &mp->blen, len))
		return;

	memmove(mp->mbuf, p, len);
	mp->len = len;
	mp->flags = inv_video ? M_INV_VIDEO : 0;
}

/*
 * msgrpt --
 *	Report on the lines that changed.
 */
int
msg_rpt(sp, fp)
	SCR *sp;
	FILE *fp;
{
	static const char *const action[] = {
		"added", "changed", "copied", "deleted", "joined", "moved",	
		"put", "read", "left shifted", "right shifted", "yanked",
		NULL,
	};
	recno_t total;
	int first, cnt;
	size_t blen, len;
	const char *const *ap;
	char *bp, *p, number[40];

	GET_SPACE(sp, bp, blen, 512);
	p = bp;

	total = 0;
	for (ap = action, cnt = 0, first = 1; *ap != NULL; ++ap, ++cnt)
		if (sp->rptlines[cnt] != 0) {
			total += sp->rptlines[cnt];
			len = snprintf(number, sizeof(number),
			    "%s%lu line%s %s", first ? "" : "; ",
			    sp->rptlines[cnt],
			    sp->rptlines[cnt] > 1 ? "s" : "", *ap);
			memmove(p, number, len);
			p += len;
			first = 0;
		}

	/* If nothing to report, return. */
	if (total != 0 && total >= O_VAL(sp, O_REPORT)) {
		*p = '\0';

		if (fp != NULL)
			(void)fprintf(fp, "%s\n", bp);
		else
			msgq(sp, M_INFO, "%s", bp);
	}

	FREE_SPACE(sp, bp, blen);

	/* Clear after each report. */
	memset(sp->rptlines, 0, sizeof(sp->rptlines));
	return (0);
}

/*
 * binc --
 *	Increase the size of a buffer.
 */
int
binc(sp, argp, bsizep, min)
	SCR *sp;			/* MAY BE NULL */
	void *argp;
	size_t *bsizep, min;
{
	void *bpp;
	size_t csize;

	/* If already larger than the minimum, just return. */
	csize = *bsizep;
	if (min && csize >= min)
		return (0);

	csize += MAX(min, 256);
	bpp = *(char **)argp;

	/* For non-ANSI C realloc implementations. */
	if (bpp == NULL)
		bpp = malloc(csize);
	else
		bpp = realloc(bpp, csize);
	if (bpp == NULL) {
		if (sp != NULL)
			msgq(sp, M_ERR, "Error: %s.", strerror(errno));
		*bsizep = 0;
		return (1);
	}
	*(char **)argp = bpp;
	*bsizep = csize;
	return (0);
}

/*
 * nonblank --
 *	Set the column number of the first non-blank character of the
 *	line.
 */
int
nonblank(sp, ep, lno, cnop)
	SCR *sp;
	EXF *ep;
	recno_t lno;
	size_t *cnop;
{
	char *p;
	size_t cnt, len;

	if ((p = file_gline(sp, ep, lno, &len)) == NULL) {
		if (file_lline(sp, ep, &lno))
			return (1);
		if (lno == 0) {
			*cnop = 0;
			return (0);
		}
		GETLINE_ERR(sp, lno);
		return (1);
	}
	if (len == 0) {
		*cnop = 0;
		return (0);
	}
	for (cnt = 0; len && isspace(*p); ++cnt, ++p, --len);
	*cnop = len ? cnt : cnt - 1;
	return (0);
}

/*
 * tail --
 *	Return tail of a path.
 */
char *
tail(path)
	char *path;
{
	char *p;

	if ((p = strrchr(path, '/')) == NULL)
		return (path);
	return (p + 1);
}

/*
 * set_window_size --
 *	Set the window size, the row may be provided as an argument.
 */
int
set_window_size(sp, set_row)
	SCR *sp;
	u_int set_row;
{
	struct winsize win;
	size_t col, row;
	int isset;
	char *argv[2], *s, buf[2048];

	row = 24;
	col = 80;

	/*
	 * Get the screen rows and columns.  If the values are wrong, it's
	 * not a big deal -- as soon as the user sets them explicitly the
	 * environment will be set and the screen package will use the new
	 * values.
	 *
	 * Try TIOCGWINSZ, followed by the termcap entry.
	 */
	if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) != -1 &&
	    win.ws_row != 0 && win.ws_col != 0) {
		row = win.ws_row;
		col = win.ws_col;
	} else {
		s = NULL;
		if (F_ISSET(&sp->opts[O_TERM], OPT_SET))
			s = O_STR(sp, O_TERM);
		else
			s = getenv("TERM");
		if (s != NULL && tgetent(buf, s) == 1) {
			row = tgetnum("li");
			col = tgetnum("co");
		}
	}

	/* POSIX 1003.2 requires the environment to override. */
	if ((s = getenv("ROWS")) != NULL)
		row = strtol(s, NULL, 10);
	if ((s = getenv("COLUMNS")) != NULL)
		col = strtol(s, NULL, 10);

	/* But, if we got an argument for the rows, use it. */
	if (set_row)
		row = set_row;

	argv[0] = buf;
	argv[1] = NULL;

	/*
	 * Tell the options code that the screen size has changed.
	 * Since the user didn't do the set, clear the set bits.
	 */
	isset = F_ISSET(&sp->opts[O_LINES], OPT_SET);
	(void)snprintf(buf, sizeof(buf), "ls=%u", row);
	if (opts_set(sp, argv))
		return (1);
	if (isset)
		F_CLR(&sp->opts[O_LINES], OPT_SET);
	isset = F_ISSET(&sp->opts[O_COLUMNS], OPT_SET);
	(void)snprintf(buf, sizeof(buf), "co=%u", col);
	if (opts_set(sp, argv))
		return (1);
	if (isset)
		F_CLR(&sp->opts[O_COLUMNS], OPT_SET);
	return (0);
}