/*- * Copyright (c) 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[] = "@(#)screen.c 8.1 (Berkeley) 6/9/93"; #endif /* not lint */ #include <sys/types.h> #include <errno.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "vi.h" #include "excmd.h" #include "tag.h" static int cut_copy __P((SCR *, SCR *)); static int opt_copy __P((SCR *, SCR *)); static int seq_copy __P((SCR *, SCR *)); static int tag_copy __P((SCR *, SCR *)); /* * scr_init -- * Do the default initialization of an SCR structure. */ int scr_init(orig, sp) SCR *orig, *sp; { extern CHNAME asciiname[]; /* XXX */ sigset_t bmask, omask; int nore; /* INITIALIZED AT SCREEN CREATE. */ /* * NULL the sp->ep field first, so the recovery timer won't access. * Block SIGALRM and SIGHUP when manipulating the SCR chain. */ memset(sp, 0, sizeof(SCR)); if (orig != NULL) { sigemptyset(&bmask); sigaddset(&bmask, SIGALRM); sigaddset(&bmask, SIGHUP); (void)sigprocmask(SIG_BLOCK, &bmask, &omask); HDR_APPEND(sp, orig, next, prev, SCR); (void)sigprocmask(SIG_SETMASK, &omask, NULL); } sp->olno = OOBLNO; sp->lno = 1; sp->cno = sp->ocno = 0; #ifdef FWOPEN_NOT_AVAILABLE sp->trapped_fd = -1; #endif FD_ZERO(&sp->rdfd); HDR_INIT(sp->bhdr, next, prev); HDR_INIT(sp->txthdr, next, prev); sp->lastcmd = &cmds[C_PRINT]; /* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ if (orig != NULL) { sp->gp = orig->gp; /* User can replay the last input, but nothing else. */ if (orig->rep_len != 0) if ((sp->rep = malloc(orig->rep_len)) == NULL) goto mem; else { memmove(sp->rep, orig->rep, orig->rep_len); sp->rep_len = orig->rep_len; } if (orig->VB != NULL && (sp->VB = strdup(orig->VB)) == NULL) goto mem; if (orig->lastbcomm != NULL && (sp->lastbcomm = strdup(orig->lastbcomm)) == NULL) goto mem; if (orig->altfname != NULL && (sp->altfname = strdup(orig->altfname)) == NULL) goto mem; sp->inc_lastch = orig->inc_lastch; sp->inc_lastval = orig->inc_lastval; if (orig->paragraph != NULL && (sp->paragraph = strdup(orig->paragraph)) == NULL) goto mem; if (cut_copy(orig, sp)) goto mem; if (tag_copy(orig, sp)) goto mem; /* Retain all searching/substitution information. */ if (orig->searchdir == NOTSET) sp->searchdir = NOTSET; else { sp->sre = orig->sre; sp->searchdir = FORWARD; } sp->csearchdir = CNOTSET; sp->lastckey = orig->lastckey; nore = 0; if (orig->matchsize && (sp->match = malloc(orig->matchsize * sizeof(regmatch_t))) == NULL) goto mem; else { if (sp->matchsize = orig->matchsize) memmove(sp->match, orig->match, orig->matchsize * sizeof(regmatch_t)); } if (sp->repl_len && (sp->repl = malloc(orig->repl_len)) == NULL) goto mem; else { if (sp->repl_len = orig->repl_len) memmove(sp->repl, orig->repl, orig->repl_len); } if (sp->newl_len && (sp->newl = malloc(orig->newl_len * sizeof(size_t))) == NULL) goto mem; else { sp->newl_len = orig->newl_len; if (sp->newl_cnt = orig->newl_cnt) memmove(sp->newl, orig->newl, orig->newl_len * sizeof(size_t)); } if (!nore && F_ISSET(orig, S_RE_SET)) F_SET(sp, S_RE_SET); sp->cname = orig->cname; memmove(sp->special, orig->special, sizeof(sp->special)); if (seq_copy(orig, sp)) goto mem; if (opt_copy(orig, sp)) { mem: msgq(orig, M_ERR, "new screen attributes: %s", strerror(errno)); scr_end(sp); return (1); } sp->flags = orig->flags & S_SCREEN_RETAIN; sp->flags |= S_REDRAW | S_REFORMAT; } else { if (isatty(STDIN_FILENO)) F_SET(sp, S_ISFROMTTY); sp->inc_lastch = '+'; sp->inc_lastval = 1; HDR_INIT(sp->taghdr, next, prev); sp->searchdir = NOTSET; sp->csearchdir = CNOTSET; sp->cname = asciiname; /* XXX */ sp->flags |= S_REDRAW | S_REFORMAT; } return (0); } /* * scr_end -- * Release a screen. */ int scr_end(sp) SCR *sp; { sigset_t bmask, omask; /* Free the memory map. */ if (sp->h_smap != NULL) FREE(sp->h_smap, sp->w_rows * sizeof(SMAP)); /* Free the argument list. */ { int cnt; for (cnt = 0; cnt < sp->argscnt; ++cnt) if (F_ISSET(&sp->args[cnt], A_ALLOCATED)) FREE(sp->args[cnt].bp, sp->args[cnt].len); FREE(sp->args, sp->argscnt * sizeof(ARGS *)); FREE(sp->argv, sp->argscnt * sizeof(char *)); } /* Free line input buffer. */ if (sp->ibp != NULL) FREE(sp->ibp, sp->ibp_len); /* Free text input, command chains. */ hdr_text_free(&sp->txthdr); hdr_text_free(&sp->bhdr); /* Free vi text input memory. */ if (sp->rep != NULL) FREE(sp->rep, sp->rep_len); /* Free visual bell termcap string. */ if (sp->VB != NULL) FREE(sp->VB, strlen(sp->VB) + 1); /* Free last bang command. */ if (sp->lastbcomm != NULL) FREE(sp->lastbcomm, strlen(sp->lastbcomm) + 1); if (sp->altfname != NULL) FREE(sp->altfname, strlen(sp->altfname) + 1); /* Free cut buffers. */ { CB *cb; int cnt; for (cb = sp->cuts, cnt = 0; cnt < UCHAR_MAX; ++cb, ++cnt) if (cb->txthdr.next != NULL) hdr_text_free(&cb->txthdr); } /* Free paragraph search list. */ if (sp->paragraph != NULL) FREE(sp->paragraph, strlen(sp->paragraph) + 1); /* Free up tag information. */ { int cnt; if (F_ISSET(&sp->opts[O_TAGS], OPT_ALLOCATED) && sp->tfhead != NULL) { for (cnt = 0; sp->tfhead[cnt] != NULL; ++cnt) FREE(sp->tfhead[cnt]->fname, strlen(sp->tfhead[cnt]->fname) + 1); free(sp->tfhead); } if (sp->tlast != NULL) FREE(sp->tlast, strlen(sp->tlast) + 1); } { TAG *tp; while ((tp = sp->taghdr.next) != (TAG *)&sp->taghdr) { HDR_DELETE(tp, next, prev, TAG); FREE(tp, sizeof(TAG)); } } /* Free up search information. */ if (sp->match != NULL) FREE(sp->match, sizeof(regmatch_t)); if (sp->repl != NULL) FREE(sp->repl, sp->repl_len); if (sp->newl != NULL) FREE(sp->newl, sp->newl_len); /* Free up linked lists of sequences. */ { SEQ *qp, *next; for (qp = sp->seqhdr.next; qp != (SEQ *)&sp->seqhdr; qp = next) { next = qp->next; if (qp->name != NULL) FREE(qp->name, strlen(qp->name) + 1); FREE(qp->output, strlen(qp->output) + 1); FREE(qp->input, strlen(qp->input) + 1); FREE(qp, sizeof(SEQ)); } } /* Free up executed buffer. */ if (sp->atkey_buf) FREE(sp->atkey_buf, sp->atkey_len); /* * Free the message chain last, so previous failures have a place * to put messages. Copy messages to (in order) a related screen, * any screen, the global area. */ { SCR *c_sp; MSG *c_mp, *mp, *next; if (sp->parent != NULL) { c_sp = sp->parent; c_mp = c_sp->msgp; if (F_ISSET(sp, S_BELLSCHED)) F_SET(c_sp, S_BELLSCHED); } else if (sp->child != NULL) { c_sp = sp->child; c_mp = c_sp->msgp; if (F_ISSET(sp, S_BELLSCHED)) F_SET(c_sp, S_BELLSCHED); } else if (sp->next != (SCR *)&sp->gp->scrhdr) { c_sp = sp->next; c_mp = c_sp->msgp; if (F_ISSET(sp, S_BELLSCHED)) F_SET(c_sp, S_BELLSCHED); } else { c_sp = NULL; c_mp = sp->gp->msgp; if (F_ISSET(sp, S_BELLSCHED)) F_SET(sp->gp, S_BELLSCHED); } for (mp = sp->msgp; mp != NULL && !F_ISSET(mp, M_EMPTY); mp = mp->next) msg_app(sp->gp, c_sp, mp->flags & M_INV_VIDEO, mp->mbuf, mp->len); for (mp = sp->msgp; mp != NULL; mp = next) { next = mp->next; if (mp->mbuf != NULL) FREE(mp->mbuf, mp->blen); FREE(mp, sizeof(MSG)); } } /* * Remove the screen from the global chain of screens. * Block SIGALRM and SIGHUP when manipulating the SCR chain. */ sigemptyset(&bmask); sigaddset(&bmask, SIGALRM); sigaddset(&bmask, SIGHUP); (void)sigprocmask(SIG_BLOCK, &bmask, &omask); HDR_DELETE(sp, next, prev, SCR); (void)sigprocmask(SIG_SETMASK, &omask, NULL); /* Remove the screen from the chain of related screens. */ if (sp->parent != NULL) { sp->parent->child = sp->child; if (sp->child != NULL) sp->child->parent = sp->parent; } else if (sp->child != NULL) sp->child->parent = NULL; /* Free the screen itself. */ FREE(sp, sizeof(SCR)); return (0); } /* * cut_copy -- * Copy a screen's cut buffers. */ static int cut_copy(a, b) SCR *a, *b; { CB *acb, *bcb; TEXT *atp, *tp; int cnt; for (acb = a->cuts, bcb = b->cuts, cnt = 0; cnt < UCHAR_MAX; ++acb, ++bcb, ++cnt) { if (acb->txthdr.next == NULL || acb->txthdr.next == &acb->txthdr) continue; HDR_INIT(bcb->txthdr, next, prev); for (atp = acb->txthdr.next; atp != (TEXT *)&acb->txthdr; atp = atp->next) { if ((tp = malloc(sizeof(TEXT))) == NULL) return (1); if ((tp->lb = malloc(atp->len)) == NULL) { FREE(tp, sizeof(TEXT)); return (1); } tp->lb_len = tp->len = atp->len; tp->wd = NULL; memmove(tp->lb, atp->lb, atp->len); HDR_INSERT(tp, &bcb->txthdr, next, prev, TEXT); } bcb->len = acb->len; bcb->flags = acb->flags; } return (0); } /* * opt_copy -- * Copy a screen's OPTION array. */ static int opt_copy(a, b) SCR *a, *b; { OPTION *op; int cnt; /* Copy most everything without change. */ memmove(b->opts, a->opts, sizeof(a->opts)); /* * Allocate copies of the strings -- keep trying to reallocate * after ENOMEM failure, otherwise end up with more than one * screen referencing the original memory. */ for (op = b->opts, cnt = 0; cnt < O_OPTIONCOUNT; ++cnt, ++op) if (F_ISSET(&b->opts[cnt], OPT_ALLOCATED) && (O_STR(b, cnt) = strdup(O_STR(b, cnt))) == NULL) { msgq(a, M_ERR, "Error: option copy: %s", strerror(errno)); return (1); } return (0); } /* * seq_copy -- * Copy a screen's SEQ structures. */ static int seq_copy(a, b) SCR *a, *b; { SEQ *ap; /* Initialize linked list. */ HDR_INIT(b->seqhdr, next, prev); for (ap = a->seqhdr.next; ap != (SEQ *)&a->seqhdr; ap = ap->next) if (seq_set(b, ap->name, ap->input, ap->output, ap->stype, F_ISSET(ap, S_USERDEF))) return (1); return (0); } /* * tag_copy -- * Copy a screen's tag structures. */ static int tag_copy(a, b) SCR *a, *b; { TAG *ap, *tp; TAGF **atfp, **btfp; int cnt; /* Initialize linked list. */ HDR_INIT(b->taghdr, next, prev); for (ap = a->taghdr.next; ap != (TAG *)&a->taghdr; ap = ap->next) { if ((tp = malloc(sizeof(TAG))) == NULL) goto nomem; *tp = *ap; HDR_INSERT(tp, &b->taghdr, next, prev, TAG); } /* Copy the list of tag files. */ for (atfp = a->tfhead, cnt = 1; *atfp != NULL; ++atfp, ++cnt); if (cnt > 1) { if ((b->tfhead = malloc(cnt * sizeof(TAGF **))) == NULL) goto nomem; for (atfp = a->tfhead, btfp = b->tfhead; *atfp != NULL; ++atfp, ++btfp) { if ((*btfp = malloc(sizeof(TAGF))) == NULL) goto nomem; if (((*btfp)->fname = strdup((*atfp)->fname)) == NULL) { FREE(*btfp, sizeof(TAGF)); *btfp = NULL; goto nomem; } (*btfp)->flags = 0; } *btfp = NULL; } /* Copy the last tag. */ if (a->tlast != NULL && (b->tlast = strdup(a->tlast)) == NULL) goto nomem; return (0); nomem: msgq(a, M_ERR, "Error: tag copy: %s", strerror(errno)); return (1); }