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