1 /*- 2 * Copyright (c) 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1993, 1994, 1995, 1996 5 * Keith Bostic. All rights reserved. 6 * 7 * See the LICENSE file for redistribution information. 8 */ 9 10 #include "config.h" 11 12 #ifndef lint 13 static const char sccsid[] = "@(#)screen.c 10.15 (Berkeley) 9/15/96"; 14 #endif /* not lint */ 15 16 #include <sys/types.h> 17 #include <sys/queue.h> 18 #include <sys/time.h> 19 20 #include <bitstring.h> 21 #include <errno.h> 22 #include <limits.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "common.h" 29 #include "../vi/vi.h" 30 31 /* 32 * screen_init -- 33 * Do the default initialization of an SCR structure. 34 * 35 * PUBLIC: int screen_init __P((GS *, SCR *, SCR **)); 36 */ 37 int 38 screen_init(gp, orig, spp) 39 GS *gp; 40 SCR *orig, **spp; 41 { 42 SCR *sp; 43 size_t len; 44 45 *spp = NULL; 46 CALLOC_RET(orig, sp, SCR *, 1, sizeof(SCR)); 47 *spp = sp; 48 49 /* INITIALIZED AT SCREEN CREATE. */ 50 sp->id = ++gp->id; 51 sp->refcnt = 1; 52 53 sp->gp = gp; /* All ref the GS structure. */ 54 55 sp->ccnt = 2; /* Anything > 1 */ 56 57 /* 58 * XXX 59 * sp->defscroll is initialized by the opts_init() code because 60 * we don't have the option information yet. 61 */ 62 63 CIRCLEQ_INIT(&sp->tiq); 64 65 /* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */ 66 if (orig == NULL) { 67 sp->searchdir = NOTSET; 68 } else { 69 /* Alternate file name. */ 70 if (orig->alt_name != NULL && 71 (sp->alt_name = strdup(orig->alt_name)) == NULL) 72 goto mem; 73 74 /* Last executed at buffer. */ 75 if (F_ISSET(orig, SC_AT_SET)) { 76 F_SET(sp, SC_AT_SET); 77 sp->at_lbuf = orig->at_lbuf; 78 } 79 80 /* Retain searching/substitution information. */ 81 sp->searchdir = orig->searchdir == NOTSET ? NOTSET : FORWARD; 82 if (orig->re != NULL && (sp->re = 83 v_strdup(sp, orig->re, orig->re_len)) == NULL) 84 goto mem; 85 sp->re_len = orig->re_len; 86 if (orig->subre != NULL && (sp->subre = 87 v_strdup(sp, orig->subre, orig->subre_len)) == NULL) 88 goto mem; 89 sp->subre_len = orig->subre_len; 90 if (orig->repl != NULL && (sp->repl = 91 v_strdup(sp, orig->repl, orig->repl_len)) == NULL) 92 goto mem; 93 sp->repl_len = orig->repl_len; 94 if (orig->newl_len) { 95 len = orig->newl_len * sizeof(size_t); 96 MALLOC(sp, sp->newl, size_t *, len); 97 if (sp->newl == NULL) { 98 mem: msgq(orig, M_SYSERR, NULL); 99 goto err; 100 } 101 sp->newl_len = orig->newl_len; 102 sp->newl_cnt = orig->newl_cnt; 103 memcpy(sp->newl, orig->newl, len); 104 } 105 106 if (opts_copy(orig, sp)) 107 goto err; 108 109 F_SET(sp, F_ISSET(orig, SC_EX | SC_VI)); 110 } 111 112 if (ex_screen_copy(orig, sp)) /* Ex. */ 113 goto err; 114 if (v_screen_copy(orig, sp)) /* Vi. */ 115 goto err; 116 117 *spp = sp; 118 return (0); 119 120 err: screen_end(sp); 121 return (1); 122 } 123 124 /* 125 * screen_end -- 126 * Release a screen, no matter what had (and had not) been 127 * initialized. 128 * 129 * PUBLIC: int screen_end __P((SCR *)); 130 */ 131 int 132 screen_end(sp) 133 SCR *sp; 134 { 135 int rval; 136 137 /* If multiply referenced, just decrement the count and return. */ 138 if (--sp->refcnt != 0) 139 return (0); 140 141 /* 142 * Remove the screen from the displayed queue. 143 * 144 * If a created screen failed during initialization, it may not 145 * be linked into the chain. 146 */ 147 if (sp->q.cqe_next != NULL) 148 CIRCLEQ_REMOVE(&sp->gp->dq, sp, q); 149 150 /* The screen is no longer real. */ 151 F_CLR(sp, SC_SCR_EX | SC_SCR_VI); 152 153 rval = 0; 154 #ifdef HAVE_PERL_INTERP 155 if (perl_screen_end(sp)) /* End perl. */ 156 rval = 1; 157 #endif 158 if (v_screen_end(sp)) /* End vi. */ 159 rval = 1; 160 if (ex_screen_end(sp)) /* End ex. */ 161 rval = 1; 162 163 /* Free file names. */ 164 { char **ap; 165 if (!F_ISSET(sp, SC_ARGNOFREE) && sp->argv != NULL) { 166 for (ap = sp->argv; *ap != NULL; ++ap) 167 free(*ap); 168 free(sp->argv); 169 } 170 } 171 172 /* Free any text input. */ 173 if (sp->tiq.cqh_first != NULL) 174 text_lfree(&sp->tiq); 175 176 /* Free alternate file name. */ 177 if (sp->alt_name != NULL) 178 free(sp->alt_name); 179 180 /* Free up search information. */ 181 if (sp->re != NULL) 182 free(sp->re); 183 if (F_ISSET(sp, SC_RE_SEARCH)) 184 regfree(&sp->re_c); 185 if (sp->subre != NULL) 186 free(sp->subre); 187 if (F_ISSET(sp, SC_RE_SUBST)) 188 regfree(&sp->subre_c); 189 if (sp->repl != NULL) 190 free(sp->repl); 191 if (sp->newl != NULL) 192 free(sp->newl); 193 194 /* Free all the options */ 195 opts_free(sp); 196 197 /* Free the screen itself. */ 198 free(sp); 199 200 return (rval); 201 } 202 203 /* 204 * screen_next -- 205 * Return the next screen in the queue. 206 * 207 * PUBLIC: SCR *screen_next __P((SCR *)); 208 */ 209 SCR * 210 screen_next(sp) 211 SCR *sp; 212 { 213 GS *gp; 214 SCR *next; 215 216 /* Try the display queue, without returning the current screen. */ 217 gp = sp->gp; 218 for (next = gp->dq.cqh_first; 219 next != (void *)&gp->dq; next = next->q.cqe_next) 220 if (next != sp) 221 break; 222 if (next != (void *)&gp->dq) 223 return (next); 224 225 /* Try the hidden queue; if found, move screen to the display queue. */ 226 if (gp->hq.cqh_first != (void *)&gp->hq) { 227 next = gp->hq.cqh_first; 228 CIRCLEQ_REMOVE(&gp->hq, next, q); 229 CIRCLEQ_INSERT_HEAD(&gp->dq, next, q); 230 return (next); 231 } 232 return (NULL); 233 } 234