/*- * 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); }