xref: /openbsd-src/usr.bin/vi/common/screen.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
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