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